web-dev-qa-db-ja.com

.NET:httpを使用してサーバーにファイルをアップロード

私は実行状態の_.php_スクリプトを使用して、URLをヒットし、単一の/複数のファイル_.csv_をアップロードします。これらのファイルには、固有のtokenが送信されます(本文はAFAIK)。以下は実際のスニペットです。

PHP:

_<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$ch = curl_init('http://demo.schooling.net/school/attendance');

$DirPath = "E:/Uploads/";

$ZKFiles=array();

if ($dh = opendir($DirPath)) 
{
    while (($file = readdir($dh)) !== false) 
    {
        if ($file == '.' || $file == '..') 
        {
            continue;
        }
        $ZKFiles[]='@'.$DirPath.$file;       
    }
    closedir($dh);
}
if(!empty($ZKFiles))
{
    // Assign POST data
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch,CURLOPT_FAILONERROR,false);
    curl_setopt_custom_postfields($ch, array('Files[]'=>$ZKFiles,'token'=>'fe60313b0edfdfaf757f9744815454545'));
    // Execute the handle
    $execResult=curl_exec($ch);
    if($execResult=== false)
    {
        echo 'Curl error: ' . curl_error($ch);
    }
    else
    {
        echo 'Operation completed without any errors';
        echo $execResult;
    }

}


function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    $algos = hash_algos();
    $hashAlgo = null;
    foreach ( array('sha1', 'md5') as $preferred ) {
        if ( in_array($preferred, $algos) ) {
            $hashAlgo = $preferred;
            break;
        }
    }
    if ( $hashAlgo === null ) { list($hashAlgo) = $algos; }
    $boundary =
        '----------------------------' .
        substr(hash($hashAlgo, 'cURL-php-multiple-value-same-key-support' . microtime()), 0, 12);

    $body = array();
    $crlf = "\r\n";
    $fields = array();
    foreach ( $postfields as $key => $value ) {
        if ( is_array($value) ) {
            foreach ( $value as $v ) {
                $fields[] = array($key, $v);
            }
        } else {
            $fields[] = array($key, $value);
        }
    }

    //print_r($fields);die();
    foreach ( $fields as $field ) {
        list($key, $value) = $field;
        if ( strpos($value, '@') === 0 ) {
            preg_match('/^@(.*?)$/', $value, $matches);
            list($dummy, $filename) = $matches;
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"; filename="' . basename($filename) . '"';
            $body[] = 'Content-Type: application/octet-stream';
            $body[] = '';
            $body[] = file_get_contents($filename);
        } else {
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"';
            $body[] = '';
            $body[] = $value;
        }
    }
    $body[] = '--' . $boundary . '--';
    $body[] = '';
    //print_r($body);die();
    $contentType = 'multipart/form-data; boundary=' . $boundary;
    $content = join($crlf, $body);
    $contentLength = strlen($content);

    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Length: ' . $contentLength,
        'Expect: 100-continue',
        'Content-Type: ' . $contentType,
    ));
    //echo $content;die();
    curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
}
?>
_

これを.NETで実現するために、私がこれまでに試したこと(すべての可能な方法)

最初のアプローチ(WebClientを使用):

_[HttpPost]
public void SendFiles()
{
    string fileToUpload = @"E:\Uploads\demo.csv";
    string url ="http://demo.schooling.net/school/attendance";
    using (var client = new WebClient())
    {
        //sending token and then uplaoding file
        System.Collections.Specialized.NameValueCollection postData =
                        new System.Collections.Specialized.NameValueCollection()
        {
            { "token", "fe60313b0edfdfaf757f9744815454545" }
        };
        string pagesource = Encoding.UTF8.GetString(client.UploadValues(url, "POST", postData));

        //string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes("fe60313b0edfdfaf757f9744815454545"));
        client.Headers["token"] = "fe60313b0edfdfaf757f9744815454545";
        client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
        byte[] result = client.UploadFile(url, fileToUpload);
        string responseAsString = Encoding.Default.GetString(result);
    }
}
_

これはトークンをURLに送信しなかったため、ページはログインページにリダイレクトされます。

2番目のアプローチ(_.NET MultipartDataContent_を使用)

_string fileUpload = @"E:\Uploads\demo.csv";
string uri = "http://demo.schooling.net/school/attendance";
//Using built-in MultipartFormDataContent
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form1 = new MultipartFormDataContent();
FileStream fs = System.IO.File.OpenRead(fileUpload);
var streamContent = new StreamContent(fs);

var Content = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
Content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
//Add token here first
form1.Add(new StringContent("fe60313b0edfdfaf757f9744815454545"), "token");
form1.Add(Content, "csv", Path.GetFileName(fileUpload));
var response = httpClient.PostAsync(uri, form1).Result;
_

これは失敗したため、3回目の試行につながった。 (トークンは送信されませんでした)

3番目のアプローチ(cutom MultipartFormを使用して説明 here

_//Using Custom MultipartForm
MultipartForm form = new MultipartForm(url);
form.SetField("token", "fe60313b0edfdfaf757f9744815454545");

form.SendFile(@"E:\Uploads\demo.csv");
_

MultiPartForm.cs:

_using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Net;

namespace Helpers
{
    /// <summary>
    /// Allow the transfer of data files using the W3C's specification
    /// for HTTP multipart form data. Microsoft's version has a bug
    /// where it does not format the ending boundary correctly.
    /// Original version written by Gregory Prentice : [email protected]
    /// See: http://www.c-sharpcorner.com/UploadFile/gregoryprentice/DotNetBugs12062005230632PM/DotNetBugs.aspx
    /// </summary>
    public class MultipartForm
    {
        /// <summary>
        /// Holds any form fields and values that you
        /// wish to transfer with your data.
        /// </summary>
        private Hashtable coFormFields;

        /// <summary>
        /// Used mainly to avoid passing parameters to other routines.
        /// Could have been local to sendFile().
        /// </summary>
        protected HttpWebRequest coRequest;

        /// <summary>
        /// Used if we are testing and want to output the raw
        /// request, minus http headers, out to a file.
        /// </summary>
        private Stream coFileStream;

        /// <summary>
        /// Difined to build the form field data that is being
        /// passed along with the request.
        /// </summary>
        private static string CONTENT_DISP = "Content-Disposition: form-data; name=";

        /// <summary>
        /// Allows you to specify the specific version of HTTP to use for uploads.
        /// The dot NET stuff currently does not allow you to remove the continue-100 header
        /// from 1.1 and 1.0 currently has a bug in it where it adds the continue-100. MS
        /// has sent a patch to remove the continue-100 in HTTP 1.0.
        /// </summary>
        public Version TransferHttpVersion { get; set; }

        /// <summary>
        /// Used to change the content type of the file being sent.
        /// Currently defaults to: text/xml. Other options are
        /// text/plain or binary
        /// </summary>
        public string FileContentType { get; set; }

        /// <summary>
        /// Initialize our class for use to send data files.
        /// </summary>
        /// <param name="url">The web address of the recipient of the data transfer.</param>
        public MultipartForm(string url)
        {
            URL = url;
            coFormFields = new Hashtable();
            ResponseText = new StringBuilder();
            BufferSize = 1024 * 10;
            BeginBoundary = "ou812--------------8c405ee4e38917c";
            TransferHttpVersion = HttpVersion.Version11;
            //FileContentType = "text/xml";
            FileContentType = "text/csv";
        }
        //---------- BEGIN PROPERTIES SECTION ----------
        private string _BeginBoundary;
        /// <summary>
        /// The string that defines the begining boundary of
        /// our multipart transfer as defined in the w3c specs.
        /// This method also sets the Content and Ending
        /// boundaries as defined by the w3c specs.
        /// </summary>
        public string BeginBoundary
        {
            get { return _BeginBoundary; }
            set
            {
                _BeginBoundary = value;
                ContentBoundary = "--" + BeginBoundary;
                EndingBoundary = ContentBoundary + "--";
            }
        }

        /// <summary>
        /// The string that defines the content boundary of
        /// our multipart transfer as defined in the w3c specs.
        /// </summary>
        protected string ContentBoundary { get; set; }

        /// <summary>
        /// The string that defines the ending boundary of
        /// our multipart transfer as defined in the w3c specs.
        /// </summary>
        protected string EndingBoundary { get; set; }

        /// <summary>
        /// The data returned to us after the transfer is completed.
        /// </summary>
        public StringBuilder ResponseText { get; set; }

        /// <summary>
        /// The web address of the recipient of the transfer.
        /// </summary>
        public string URL { get; set; }

        /// <summary>
        /// Allows us to determine the size of the buffer used
        /// to send a piece of the file at a time out the IO
        /// stream. Defaults to 1024 * 10.
        /// </summary>
        public int BufferSize { get; set; }

        //---------- END PROPERTIES SECTION ----------

        /// <summary>
        /// Used to signal we want the output to go to a
        /// text file verses being transfered to a URL.
        /// </summary>
        /// <param name="path"></param>
        public void SetFilename(string path)
        {
            coFileStream = new System.IO.FileStream(path, FileMode.Create, FileAccess.Write);
        }
        /// <summary>
        /// Allows you to add some additional field data to be
        /// sent along with the transfer. This is usually used
        /// for things like userid and password to validate the
        /// transfer.
        /// </summary>
        /// <param name="key">The form field name</param>
        /// <param name="str">The form field value</param>
        public void SetField(string key, string str)
        {
            coFormFields[key] = str;
        }
        /// <summary>
        /// Determines if we have a file stream set, and returns either
        /// the HttpWebRequest stream of the file.
        /// </summary>
        /// <returns></returns>
        public virtual Stream GetStream()
        {
            Stream stream;
            if (null == coFileStream)
                stream = coRequest.GetRequestStream();
            else
                stream = coFileStream;
            return stream;
        }
        /// <summary>
        /// Here we actually make the request to the web server and
        /// retrieve it's response into a text buffer.
        /// </summary>
        public virtual void GetResponse()
        {
            if (null == coFileStream)
            {
                Stream stream;
                WebResponse response;
                try
                {
                    response = coRequest.GetResponse();
                }
                catch (WebException web)
                {
                    response = web.Response;
                }
                if (null != response)
                {
                    stream = response.GetResponseStream();
                    StreamReader sr = new StreamReader(stream);
                    string str;
                    ResponseText.Length = 0;
                    while ((str = sr.ReadLine()) != null)
                        ResponseText.Append(str);
                    response.Close();
                }
                else
                    throw new Exception("MultipartForm: Error retrieving server response");
            }
        }
        /// <summary>
        /// Transmits a file to the web server stated in the
        /// URL property. You may call this several times and it
        /// will use the values previously set for fields and URL.
        /// </summary>
        /// <param name="filename">The full path of file being transfered.</param>
        public void SendFile(string filename)
        {
            // The live of this object is only good during
            // this function. Used mainly to avoid passing
            // around parameters to other functions.
            coRequest = (HttpWebRequest)WebRequest.Create(URL);
            // Set use HTTP 1.0 or 1.1.
            coRequest.ProtocolVersion = TransferHttpVersion;
            coRequest.Method = "POST";
            coRequest.ContentType = "multipart/form-data; boundary=" + BeginBoundary;
            coRequest.Headers.Add("Cache-Control", "no-cache");
            coRequest.KeepAlive = true;
            string strFields = GetFormfields();
            string strFileHdr = GetFileheader(filename);
            string strFileTlr = GetFiletrailer();
            FileInfo info = new FileInfo(filename);
            coRequest.ContentLength = strFields.Length +
              strFileHdr.Length +
              strFileTlr.Length +
              info.Length;
            System.IO.Stream io;
            io = GetStream();
            WriteString(io, strFields);
            WriteString(io, strFileHdr);
            this.WriteFile(io, filename);
            WriteString(io, strFileTlr);
            GetResponse();
            io.Close();
            // End the life time of this request object.
            coRequest = null;
        }
        /// <summary>
        /// Mainly used to turn the string into a byte buffer and then
        /// write it to our IO stream.
        /// </summary>
        /// <param name="stream">The io stream for output.</param>
        /// <param name="str">The data to write.</param>
        public void WriteString(Stream stream, string str)
        {
            byte[] postData = System.Text.Encoding.ASCII.GetBytes(str);
            stream.Write(postData, 0, postData.Length);
        }
        /// <summary>
        /// Builds the proper format of the multipart data that
        /// contains the form fields and their respective values.
        /// </summary>
        /// <returns>The data to send in the multipart upload.</returns>
        public string GetFormfields()
        {
            string str = "";
            IDictionaryEnumerator myEnumerator = coFormFields.GetEnumerator();
            while (myEnumerator.MoveNext())
            {
                str += ContentBoundary + "\r\n" +
                  CONTENT_DISP + '"' + myEnumerator.Key + "\"\r\n\r\n" +
                  myEnumerator.Value + "\r\n";
            }
            return str;
        }
        /// <summary>
        /// Returns the proper content information for the
        /// file we are sending.
        /// </summary>
        /// <remarks>
        /// Hits Patel reported a bug when used with ActiveFile.
        /// Added semicolon after sendfile to resolve that issue.
        /// Tested for compatibility with IIS 5.0 and Java.
        /// </remarks>
        /// <param name="filename"></param>
        /// <returns></returns>
        public string GetFileheader(string filename)
        {
            return ContentBoundary + "\r\n" +
              CONTENT_DISP +
              "\"sendfile\"; filename=\"" +
              Path.GetFileName(filename) + "\"\r\n" +
              "Content-type: " + FileContentType + "\r\n\r\n";
        }
        /// <summary>
        /// Creates the proper ending boundary for the multipart upload.
        /// </summary>
        /// <returns>The ending boundary.</returns>
        public string GetFiletrailer()
        {
            return "\r\n" + EndingBoundary;
        }
        /// <summary>
        /// Reads in the file a chunck at a time then sends it to the
        /// output stream.
        /// </summary>
        /// <param name="stream">The io stream to write the file to.</param>
        /// <param name="filename">The name of the file to transfer.</param>
        public void WriteFile(Stream stream, string filename)
        {
            using (FileStream readIn = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                readIn.Seek(0, SeekOrigin.Begin); // move to the start of the file
                byte[] fileData = new byte[BufferSize];
                int bytes;
                while ((bytes = readIn.Read(fileData, 0, BufferSize)) > 0)
                {
                    // read the file data and send a chunk at a time
                    stream.Write(fileData, 0, bytes);
                }
            }
        }
    }
}
_

運が悪いが、許容範囲が広い場合、4回目の試行が行われます(このアプローチでもトークンは送信されませんでした)

4番目のアプローチ(HttpClientを使用)

_using (var client = new HttpClient())
{
    using (var multipartFormDataContent = new MultipartFormDataContent())
    {
        var values = new[]
        {

    new KeyValuePair<string, string>("token", "fe60313b0edfdfaf757f9744815454545")
     //other values
};

        foreach (var keyValuePair in values)
        {
            multipartFormDataContent.Add(new StringContent(keyValuePair.Value),
                String.Format("\"{0}\"", keyValuePair.Key));
        }

        multipartFormDataContent.Add(new ByteArrayContent(System.IO.File.ReadAllBytes(@"E:\\Uploads\\demo.csv")),
            '"' + "File" + '"',
            '"' + "democollege.csv" + '"');
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", "fe60313b0edfdfaf757f9744815454545");
        var requestUri = "http://demo.schooling.net/school/attendance";
        var result = client.PostAsync(requestUri, multipartFormDataContent).Result;
    }
}
_

これも私を撃墜しました、再びトークンはなく、最終的にファイルはアップロードされませんでした

5番目のアプローチ(HttpWebRequestを使用)

_   public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc)
        {
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
            wr.ContentType = "multipart/form-data; boundary=" + boundary;
            wr.Method = "POST";
            wr.KeepAlive = true;
            wr.AllowAutoRedirect = false;
           // wr.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "Your Oauth token");
            wr.Headers.Add("Authorization", "Basic " + "fe60313b0edfdfaf757f9744815454545");
            wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
            Stream rs = wr.GetRequestStream();
            string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
            foreach (string key in nvc.Keys)
            {
                rs.Write(boundarybytes, 0, boundarybytes.Length);
                string formitem = string.Format(formdataTemplate, key, nvc[key]);
                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                rs.Write(formitembytes, 0, formitembytes.Length);
            }
            rs.Write(boundarybytes, 0, boundarybytes.Length);
            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
            string header = string.Format(headerTemplate, paramName, file, contentType);
            byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
            rs.Write(headerbytes, 0, headerbytes.Length);
            FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[4096];
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                rs.Write(buffer, 0, bytesRead);
            }
            fileStream.Close();
            byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
            rs.Write(trailer, 0, trailer.Length);
            rs.Close();
            WebResponse wresp = null;
            try
            {
                wresp = wr.GetResponse();
                Stream stream2 = wresp.GetResponseStream();
                StreamReader reader2 = new StreamReader(stream2);
                var result = reader2.ReadToEnd();
            }
            catch (Exception ex)
            {
               // System.Windows.MessageBox.Show("Error occurred while converting file", "Error!");
                if (wresp != null)
                {
                    wresp.Close();
                    wresp = null;
                }
            }
            finally
            {
                wr = null;
            }
        }
_

そしてそのメソッドを呼び出す:

_string fileToUpload = @"E:\Uploads\demo.csv";
                string url = "http://demo.schooling.net/school/attendance";
                NameValueCollection nvc = new NameValueCollection();
                nvc.Add("token", "fe60313b0edfdfaf757f9744815454545");
                HttpUploadFile(url, fileToUpload, "file", "text/csv", nvc);
_

フォームデータを取得しているにもかかわらず、これも失敗しました。 (上記の試みの1つを使用して添付された画像) enter image description here

PHPスクリプトに次の行を追加することにより:

_ ...$body[] = '';
    print_r($body);die();
_

私はこれをブラウザで見ることができます:

_Array ( [0] => Array 
( [0] => Files[] 
[1] => @E:/Uploads/demo.csv ) 
[1] => Array ( [0] => token 
[1] => fe60313b0edfdfaf757f9744815454545) ) 
_

以下の行をphpスクリプトに追加します。

_print_r($body); die();
_

function curl_setopt_custom_postfields($ch, $postfields, $headers = null);関数の最後に、ブラウザーでこれを確認できます。

_Array ( [0] => ------------------------------3c935d382987 
[1] => Content-Disposition: form-data; name="Files[]"; filename="demo.csv" 
[2] => Content-Type: application/octet-stream 
[3] => 
[4] => No,Name,Time,Verify,Mach,Ex,checktype,sid,code,Date 22364,22364,12/8/2017 10:28,Fingerpint,democollege-1-1,,I,1,0,12/8/2017 22365,22365,12/8/2017 9:29,Fingerpint,democollege-1-1,,I,1,0,12/8/2017 22366,22366,12/8/2017 10:59,Fingerpint,democollege-1-1,,I,1,0,12/8/2017 22369,22369,12/8/2017 11:58,Fingerpint,democollege-1-1,,I,1,0,12/8/2017 22364,22364,11/7/2017 10:28,Fingerpint,democollege-1-1,,I,1,0,11/7/2017 22365,22365,11/7/2017 9:29,Fingerpint,democollege-1-1,,I,1,0,11/7/2017 22366,22366,11/7/2018 10:59,Fingerpint,democollege-1-1,,I,1,0,11/7/2017 22369,22369,11/7/2018 11:58,Fingerpint,democollege-1-1,,I,1,0,11/7/2017 
[5] => ------------------------------3c935d382987 
[6] => Content-Disposition: form-data; name="token" 
[7] => 
[8] => fe60313b0edfdfaf757f9744815454545
[9] => ------------------------------3c935d382987-- 
[10] => ) 
_

バイオリン弾き:

enter image description here

14
DirtyBit

。Net Web APIファイル;アップロード、ダウンロード、画像レビュー、SendCloudサービス

Web.config

<appSettings>

 <!--FileService-->
    <add key="ftpUserName" value="fooUserName" />
    <add key="ftpPassword" value="fooPass" />

<!--FileController-->
    <add key="fileServiceLocalPath" value="~/App_Data/Upload" />
    <add key="fileServiceStoragePath" value="fooFtpAddress" />
    <add key="useCloud" value="false" />

</appSettings>

認証付きファイルコントローラ

[Authorize]
[RoutePrefix("api/File")]

 public class FileController : ApiController
    {
        IFileService fileService = null;
        public FileController(IFileService _fileService)
        {
            fileService = _fileService;
        }

        [Route("Upload"), HttpPost]
        public async Task<IHttpActionResult> Upload()
        {
            #region Condition

            if (!Request.Content.IsMimeMultipartContent())
                return Content(HttpStatusCode.UnsupportedMediaType, Messages.FUW0001);
            #endregion

            /// `localPath` and `useCloud` is get from Web.Config.
            string localPath = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["fileServiceLocalPath"]);
            bool useCloud = Convert.ToBoolean(ConfigurationManager.AppSettings["useCloud"]);

            var provider = new MultipartFormDataStreamProvider(localPath);

            try
            {
                /// Loads the files into the local storage.
                await Request.Content.ReadAsMultipartAsync(provider);

                /// Check is exist valid file.
                if (provider.FileData.Count == 0)
                    return BadRequest(Messages.FUE0001 /*Message Type FUE001 = File Not Found */);

                IList<FileDto> modelList = new List<FileDto>();

                foreach (MultipartFileData file in provider.FileData)
                {
                    string originalName = file.Headers.ContentDisposition.FileName;
                    if (originalName.StartsWith("\"") && originalName.EndsWith("\""))
                    {
                        originalName = originalName.Trim('"');
                    }
                    if (originalName.Contains(@"/") || originalName.Contains(@"\"))
                    {
                        originalName = Path.GetFileName(originalName);
                    }

                    /// File information storage my database.
                    FileDto fileDto = new FileDto
                    {
                        OriginalName = Path.GetFileNameWithoutExtension(originalName),
                        StorageName = Path.GetFileName(file.LocalFileName),
                        Extension = Path.GetExtension(originalName).ToLower().Replace(".", ""),
                        Size = new FileInfo(file.LocalFileName).Length
                    };

                    modelList.Add(fileDto);
                }

                if (useCloud)
                    await fileService.SendCloud(modelList,localPath);

                await fileService.Add(modelList, IdentityClaimsValues.UserID<Guid>());

                return Ok(Messages.Ok);
            }
            catch (Exception exMessage)
            {
                return Content(HttpStatusCode.InternalServerError, exMessage);
            }
        }

    [   Route("Download"), HttpGet]
        public async Task<IHttpActionResult> Download(Guid id)
        {
            /// Get file information my database
            var model = await fileService.GetByID(id);

            if (model == null)
                return BadRequest();

            /// `localPath` is get from Web.Config.
            string localPath = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["fileServiceLocalPath"]);

            string root = localPath + "\\" + model.StorageName;

            byte[] fileData = File.ReadAllBytes(root);
            var stream = new MemoryStream(fileData, 0, fileData.Length);

            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(stream.ToArray())
            };

            response.Content.Headers.ContentDisposition =
                new ContentDispositionHeaderValue("attachment")
                {
                    FileName = model.OriginalName + "." + model.Extension,
                    Size=model.Size
                };

            response.Content.Headers.ContentType =
                new MediaTypeHeaderValue("application/octet-stream");

            IHttpActionResult result = ResponseMessage(response);
            return result;
        }

        [Route("ImageReview"), HttpGet]
        public async Task<IHttpActionResult> ImageReview(Guid id)
        {
            /// Get file information my database
            var model = await fileService.GetByID(id);

            if (model == null)
                return BadRequest();

            /// `localPath` is get from Web.Config.
            string localPath = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["fileServiceLocalPath"]);

            string root = localPath + "\\" + model.StorageName;

            byte[] fileData = File.ReadAllBytes(root);
            var stream = new MemoryStream(fileData, 0, fileData.Length);

            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(stream)
            };

            response.Content.Headers.ContentType =
                new MediaTypeHeaderValue("image/"+ model.Extension);

            IHttpActionResult result = ResponseMessage(response);

            return result;
        }
    }

ファイルサービス

public interface IFileService
    {
        Task SendCloud(IList<FileDto> modelList, string localPath);
    }   

    public class FileService : IFileService
    {
        public Task SendCloud(IList<FileDto> modelList,string localPath)
        {
            /// `ftpUserName`, `ftpPassword` and `storagePath` is get from Web.Config.
            string ftpUserName = ConfigurationManager.AppSettings["ftpUserName"];
            string ftpPassword = ConfigurationManager.AppSettings["ftpPassword"];
            string storagePath = ConfigurationManager.AppSettings["fileServiceStoragePath"];

            /// Uploaded files are sent to the cloud server.
            foreach (var model in modelList)
            {
                FtpWebRequest req = (FtpWebRequest)WebRequest.Create(storagePath + model.StorageName);

                req.UseBinary = true;
                req.Method = WebRequestMethods.Ftp.UploadFile;
                req.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
                byte[] fileData = File.ReadAllBytes(localPath + "\\" + model.StorageName);
                req.ContentLength = fileData.Length;

                Stream reqStream = req.GetRequestStream();
                reqStream.Write(fileData, 0, fileData.Length);
                reqStream.Close();
            }

            return Task.CompletedTask;
        }

    }

ビルド用のイメージです。

Image review request for fiddler

Response

8

あなたのHttpClientMultipartFormDataContentアプローチはうまくいくと思います

入力名を探す必要があるだけなので、以下を試してください

HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();

string filename = @"E:\Uploads\demo.csv"
    , filename2 = @"E:\Uploads\demo2.csv"
    , url = "http://demo.schooling.net/school/attendance"
    , token = "fe60313b0edfdfaf757f9744815454545"
    ;
byte[] bytes = System.IO.File.ReadAllBytes(filename);


// Keep `token` here, no quote escaping
form.Add(new StringContent(token), "token");

// Keep `Files[]` here
form.Add(new ByteArrayContent(bytes), "Files[]", Path.GetFileName(filename));

// To add 2nd file, keep the input name as `Files[]`
bytes = System.IO.File.ReadAllBytes(filename2);
form.Add(new ByteArrayContent(bytes), "Files[]", Path.GetFileName(filename2));        

var result = httpClient.PostAsync(url, form).Result;
0
Neverever