簡體   English   中英

如何使用 HTTP POST multipart/form-data 將文件上傳到服務器?

[英]How to upload file to server with HTTP POST multipart/form-data?

我正在開發 Windows Phone 8 應用程序。 我想使用 HTTP POST 請求通過 8832478985188 web 服務上傳 SQLite 數據庫,MIME 類型 multipart/form-data 和一個名為“userid=SOME_ID”的字符串數據。

我不想使用像 HttpClient、RestSharp 或 MyToolkit 這樣的第三方庫。 我嘗試了下面的代碼,但它沒有上傳文件,也沒有給我任何錯誤。 它在 Android、PHP 等中工作正常,因此 web 服務沒有問題。 下面是我給定的代碼(對於 WP8)。 它出什么問題了?

我已經用谷歌搜索了,但我並沒有具體了解 WP8

async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(DBNAME);
    //Below line gives me file with 0 bytes, why? Should I use 
    //IsolatedStorageFile instead of StorageFile
    //var file = await ApplicationData.Current.LocalFolder.GetFileAsync(DBNAME);
    byte[] fileBytes = null;
    using (var stream = await file.OpenReadAsync())
    {
        fileBytes = new byte[stream.Size];
        using (var reader = new DataReader(stream))
        {
            await reader.LoadAsync((uint)stream.Size);
            reader.ReadBytes(fileBytes);
        }
    }

    //var res = await HttpPost(Util.UPLOAD_BACKUP, fileBytes);
    HttpPost(fileBytes);
}

private void HttpPost(byte[] file_bytes)
{
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.myserver.com/upload.php");
    httpWebRequest.ContentType = "multipart/form-data";
    httpWebRequest.Method = "POST";
    var asyncResult = httpWebRequest.BeginGetRequestStream((ar) => { GetRequestStreamCallback(ar, file_bytes); }, httpWebRequest);  
}

private void GetRequestStreamCallback(IAsyncResult asynchronousResult, byte[] postData)  
{
    //DON'T KNOW HOW TO PASS "userid=some_user_id"  
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;  
    Stream postStream = request.EndGetRequestStream(asynchronousResult);  
    postStream.Write(postData, 0, postData.Length);  
    postStream.Close();  
    var asyncResult = request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);  
}  

private void GetResponseCallback(IAsyncResult asynchronousResult)  
{  
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;  
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);  
    Stream streamResponse = response.GetResponseStream();  
    StreamReader streamRead = new StreamReader(streamResponse);  
    string responseString = streamRead.ReadToEnd();  
    streamResponse.Close();  
    streamRead.Close();  
    response.Close();  
}  

我也嘗試在 Windows 8 中解決我的問題,但它也不起作用。

public async Task Upload(byte[] fileBytes)
{
    using (var client = new HttpClient())
    {
        using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture)))
        {
            content.Add(new StreamContent(new MemoryStream(fileBytes)));
            //Not sure below line is true or not
            content.Add(new StringContent("userid=farhanW8"));
            using (var message = await client.PostAsync("http://www.myserver.com/upload.php", content))
            {
                var input = await message.Content.ReadAsStringAsync();
            }
        }
    }
}

使用 MultipartFormDataContent 的基本實現:-

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

form.Add(new StringContent(username), "username");
form.Add(new StringContent(useremail), "email");
form.Add(new StringContent(password), "password");            
form.Add(new ByteArrayContent(file_bytes, 0, file_bytes.Length), "profile_pic", "hello1.jpg");
HttpResponseMessage response = await httpClient.PostAsync("PostUrl", form);

response.EnsureSuccessStatusCode();
httpClient.Dispose();
string sd = response.Content.ReadAsStringAsync().Result;

這是我的最終工作代碼。 我的 Web 服務需要一個文件(POST 參數名稱為“file”)和一個字符串值(POST 參數名稱為“userid”)。

/// <summary>
/// Occurs when upload backup application bar button is clicked. Author : Farhan Ghumra
 /// </summary>
private async void btnUploadBackup_Click(object sender, EventArgs e)
{
    var dbFile = await ApplicationData.Current.LocalFolder.GetFileAsync(Util.DBNAME);
    var fileBytes = await GetBytesAsync(dbFile);
    var Params = new Dictionary<string, string> { { "userid", "9" } };
    UploadFilesToServer(new Uri(Util.UPLOAD_BACKUP), Params, Path.GetFileName(dbFile.Path), "application/octet-stream", fileBytes);
}

/// <summary>
/// Creates HTTP POST request & uploads database to server. Author : Farhan Ghumra
/// </summary>
private void UploadFilesToServer(Uri uri, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
{
    string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
    httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
    httpWebRequest.Method = "POST";
    httpWebRequest.BeginGetRequestStream((result) =>
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)result.AsyncState;
            using (Stream requestStream = request.EndGetRequestStream(result))
            {
                WriteMultipartForm(requestStream, boundary, data, fileName, fileContentType, fileData);
            }
            request.BeginGetResponse(a =>
            {
                try
                {
                    var response = request.EndGetResponse(a);
                    var responseStream = response.GetResponseStream();
                    using (var sr = new StreamReader(responseStream))
                    {
                        using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                        {
                            string responseString = streamReader.ReadToEnd();
                            //responseString is depend upon your web service.
                            if (responseString == "Success")
                            {
                                MessageBox.Show("Backup stored successfully on server.");
                            }
                            else
                            {
                                MessageBox.Show("Error occurred while uploading backup on server.");
                            } 
                        }
                    }
                }
                catch (Exception)
                {

                }
            }, null);
        }
        catch (Exception)
        {

        }
    }, httpWebRequest);
}

/// <summary>
/// Writes multi part HTTP POST request. Author : Farhan Ghumra
/// </summary>
private void WriteMultipartForm(Stream s, string boundary, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
{
    /// The first boundary
    byte[] boundarybytes = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
    /// the last boundary.
    byte[] trailer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
    /// the form data, properly formatted
    string formdataTemplate = "Content-Dis-data; name=\"{0}\"\r\n\r\n{1}";
    /// the form-data file upload, properly formatted
    string fileheaderTemplate = "Content-Dis-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";

    /// Added to track if we need a CRLF or not.
    bool bNeedsCRLF = false;

    if (data != null)
    {
        foreach (string key in data.Keys)
        {
            /// if we need to drop a CRLF, do that.
            if (bNeedsCRLF)
                WriteToStream(s, "\r\n");

            /// Write the boundary.
            WriteToStream(s, boundarybytes);

            /// Write the key.
            WriteToStream(s, string.Format(formdataTemplate, key, data[key]));
            bNeedsCRLF = true;
        }
    }

    /// If we don't have keys, we don't need a crlf.
    if (bNeedsCRLF)
        WriteToStream(s, "\r\n");

    WriteToStream(s, boundarybytes);
    WriteToStream(s, string.Format(fileheaderTemplate, "file", fileName, fileContentType));
    /// Write the file data to the stream.
    WriteToStream(s, fileData);
    WriteToStream(s, trailer);
}

/// <summary>
/// Writes string to stream. Author : Farhan Ghumra
/// </summary>
private void WriteToStream(Stream s, string txt)
{
    byte[] bytes = Encoding.UTF8.GetBytes(txt);
    s.Write(bytes, 0, bytes.Length);
}

/// <summary>
/// Writes byte array to stream. Author : Farhan Ghumra
/// </summary>
private void WriteToStream(Stream s, byte[] bytes)
{
    s.Write(bytes, 0, bytes.Length);
}

/// <summary>
/// Returns byte array from StorageFile. Author : Farhan Ghumra
/// </summary>
private async Task<byte[]> GetBytesAsync(StorageFile file)
{
    byte[] fileBytes = null;
    using (var stream = await file.OpenReadAsync())
    {
        fileBytes = new byte[stream.Size];
        using (var reader = new DataReader(stream))
        {
            await reader.LoadAsync((uint)stream.Size);
            reader.ReadBytes(fileBytes);
        }
    }

    return fileBytes;
}

我非常感謝Darin Rousseau幫助我。

這個簡單的版本也有效。

public void UploadMultipart(byte[] file, string filename, string contentType, string url)
{
    var webClient = new WebClient();
    string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
    webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
    var fileData = webClient.Encoding.GetString(file);
    var package = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n{3}\r\n--{0}--\r\n", boundary, filename, contentType, fileData);

    var nfile = webClient.Encoding.GetBytes(package);

    byte[] resp = webClient.UploadData(url, "POST", nfile);
}

如果需要,添加任何額外的必需標題。

我一直在玩,想出了一個簡化的、更通用的解決方案:

private static string sendHttpRequest(string url, NameValueCollection values, NameValueCollection files = null)
{
    string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
    // The first boundary
    byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
    // The last boundary
    byte[] trailer = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
    // The first time it itereates, we need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick
    byte[] boundaryBytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");

    // Create the request and set parameters
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.ContentType = "multipart/form-data; boundary=" + boundary;
    request.Method = "POST";
    request.KeepAlive = true;
    request.Credentials = System.Net.CredentialCache.DefaultCredentials;

    // Get request stream
    Stream requestStream = request.GetRequestStream();

    foreach (string key in values.Keys)
    {
        // Write item to stream
        byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}", key, values[key]));
        requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
        requestStream.Write(formItemBytes, 0, formItemBytes.Length);
    }

    if (files != null)
    { 
        foreach(string key in files.Keys)
        {
            if(File.Exists(files[key]))
            {
                int bytesRead = 0;
                byte[] buffer = new byte[2048];
                byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", key, files[key]));
                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                requestStream.Write(formItemBytes, 0, formItemBytes.Length);

                using (FileStream fileStream = new FileStream(files[key], FileMode.Open, FileAccess.Read))
                {
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        // Write file content to stream, byte by byte
                        requestStream.Write(buffer, 0, bytesRead);
                    }

                    fileStream.Close();
                }
            }
        }
    }

    // Write trailer and close stream
    requestStream.Write(trailer, 0, trailer.Length);
    requestStream.Close();

    using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
    {
        return reader.ReadToEnd();
    };
}

你可以這樣使用它:

string fileLocation = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "somefile.jpg";
NameValueCollection values = new NameValueCollection();
NameValueCollection files = new NameValueCollection();
values.Add("firstName", "Alan");
files.Add("profilePicture", fileLocation);
sendHttpRequest("http://example.com/handler.php", values, files);

在 PHP 腳本中,您可以像這樣處理數據:

echo $_POST['firstName'];
$name = $_POST['firstName'];
$image = $_FILES['profilePicture'];
$ds = DIRECTORY_SEPARATOR;
move_uploaded_file($image['tmp_name'], realpath(dirname(__FILE__)) . $ds . "uploads" . $ds . $image['name']);

你可以使用這個類:

using System.Collections.Specialized;
class Post_File
{
    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");
        byte[] boundarybytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");  // the first time it itereates, you need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick.  


        HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
        wr.Method = "POST";
        wr.KeepAlive = true;
        wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
        wr.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        var nvc2 = new NameValueCollection();
        nvc2.Add("Accepts-Language", "en-us,en;q=0.5");
        wr.Headers.Add(nvc2);
        wr.ContentType = "multipart/form-data; boundary=" + boundary;


        Stream rs = wr.GetRequestStream();

        bool firstLoop = true;
        string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
        foreach (string key in nvc.Keys)
        {
            if (firstLoop)
            {
                rs.Write(boundarybytesF, 0, boundarybytesF.Length);
                firstLoop = false;
            }
            else
            {
                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, new FileInfo(file).Name, 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);
        }
        catch (Exception ex)
        {
            if (wresp != null)
            {
                wresp.Close();
                wresp = null;
            }
        }
        finally
        {
            wr = null;
        }
    }
}

用它:

NameValueCollection nvc = new NameValueCollection();
//nvc.Add("id", "TTR");
nvc.Add("table_name", "uploadfile");
nvc.Add("commit", "uploadfile");
Post_File.HttpUploadFile("http://example/upload_file.php", @"C:\user\yourfile.docx", "uploadfile", "application/vnd.ms-excel", nvc);

示例服務器upload_file.php

m('File upload '.(@copy($_FILES['uploadfile']['tmp_name'],getcwd().'\\'.'/'.$_FILES['uploadfile']['name']) ? 'success' : 'failed'));
function m($msg) {
    echo '<div style="background:#f1f1f1;border:1px solid #ddd;padding:15px;font:14px;text-align:center;font-weight:bold;">';
    echo $msg;
    echo '</div>';
}

以下是將文件作為多格式數據發送時對我有用的方法:

    public T HttpPostMultiPartFileStream<T>(string requestURL, string filePath, string fileName)
    {
        string content = null;

        using (MultipartFormDataContent form = new MultipartFormDataContent())
        {
            StreamContent streamContent;
            using (var fileStream = new FileStream(filePath, FileMode.Open))
            {
                streamContent = new StreamContent(fileStream);

                streamContent.Headers.Add("Content-Type", "application/octet-stream");
                streamContent.Headers.Add("Content-Disposition", string.Format("form-data; name=\"file\"; filename=\"{0}\"", fileName));
                form.Add(streamContent, "file", fileName);

                using (HttpClient client = GetAuthenticatedHttpClient())
                {
                    HttpResponseMessage response = client.PostAsync(requestURL, form).GetAwaiter().GetResult();
                    content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();



                    try
                    {
                        return JsonConvert.DeserializeObject<T>(content);
                    }
                    catch (Exception ex)
                    {
                        // Log the exception
                    }

                    return default(T);
                }
            }
        }
    }

上面使用的 GetAuthenticatedHttpClient 可以是:

private HttpClient GetAuthenticatedHttpClient()
{
    HttpClient httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri(<yourBaseURL>));
    httpClient.DefaultRequestHeaders.Add("Token, <yourToken>);
    return httpClient;
}

下面的代碼讀取文件,將其轉換為字節數組,然后向服務器發出請求。

    public void PostImage()
    {
        HttpClient httpClient = new HttpClient();
        MultipartFormDataContent form = new MultipartFormDataContent();

        byte[] imagebytearraystring = ImageFileToByteArray(@"C:\Users\Downloads\icon.png");
        form.Add(new ByteArrayContent(imagebytearraystring, 0, imagebytearraystring.Count()), "profile_pic", "hello1.jpg");
        HttpResponseMessage response = httpClient.PostAsync("your url", form).Result;

        httpClient.Dispose();
        string sd = response.Content.ReadAsStringAsync().Result;
    }

    private byte[] ImageFileToByteArray(string fullFilePath)
    {
        FileStream fs = File.OpenRead(fullFilePath);
        byte[] bytes = new byte[fs.Length];
        fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
        fs.Close();
        return bytes;
    }

大家好,在網上搜索了一天后,我終於用下面的源代碼解決了問題,希望對您有所幫助

    public UploadResult UploadFile(string  fileAddress)
    {
        HttpClient client = new HttpClient();

        MultipartFormDataContent form = new MultipartFormDataContent();
        HttpContent content = new StringContent("fileToUpload");
        form.Add(content, "fileToUpload");       
        var stream = new FileStream(fileAddress, FileMode.Open);            
        content = new StreamContent(stream);
        var fileName = 
        content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
        {
            Name = "name",
            FileName = Path.GetFileName(fileAddress),                 
        };
        form.Add(content);
        HttpResponseMessage response = null;          

        var url = new Uri("http://192.168.10.236:2000/api/Upload2");
        response = (client.PostAsync(url, form)).Result;          

    }

我知道這是舊線程,但我正在與此作斗爭,我想分享我的解決方案。

此解決方案適用於System.Net.Http HttpClientMultipartFormDataContent 您可以使用.NET Core 1.0或更高版本或.NET Framework 4.5或更高版本發布它。

作為一個快速總結,它是一種異步方法,它接收要在其中執行 POST 的 URL、用於發送字符串的鍵/值集合和用於發送文件的鍵/值集合作為參數。

private static async Task<HttpResponseMessage> Post(string url, NameValueCollection strings, NameValueCollection files)
{
    var formContent = new MultipartFormDataContent(/* If you need a boundary, you can define it here */);

    // Strings
    foreach (string key in strings.Keys)
    {
        string inputName = key;
        string content = strings[key];

        formContent.Add(new StringContent(content), inputName);
    }

    // Files
    foreach (string key in files.Keys)
    {
        string inputName = key;
        string fullPathToFile = files[key];

        FileStream fileStream = File.OpenRead(fullPathToFile);
        var streamContent = new StreamContent(fileStream);
        var fileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
        formContent.Add(fileContent, inputName, Path.GetFileName(fullPathToFile));
    }

    var myHttpClient = new HttpClient();
    var response = await myHttpClient.PostAsync(url, formContent);
    //string stringContent = await response.Content.ReadAsStringAsync(); // If you need to read the content

    return response;
}

您可以像這樣准備您的 POST(您可以根據需要添加如此多的字符串和文件):

string url = @"http://yoursite.com/upload.php"

NameValueCollection strings = new NameValueCollection();
strings.Add("stringInputName1", "The content for input 1");
strings.Add("stringInputNameN", "The content for input N");

NameValueCollection files = new NameValueCollection();
files.Add("fileInputName1", @"FullPathToFile1"); // Path + filename
files.Add("fileInputNameN", @"FullPathToFileN");

最后,像這樣調用方法:

var result = Post(url, strings, files).GetAwaiter().GetResult();

如果需要,您可以檢查您的狀態碼,並顯示原因如下:

if (result.StatusCode == HttpStatusCode.OK)
{
    // Logic if all was OK
}
else
{
    // You can show a message like this:
    Console.WriteLine(string.Format("Error. StatusCode: {0} | ReasonPhrase: {1}", result.StatusCode, result.ReasonPhrase));
}

如果有人需要它,我在這里舉一個小例子,說明如何使用 PHP 接收存儲文件(在我們的 .Net 應用程序的另一端):

<?php

if (isset($_FILES['fileInputName1']) && $_FILES['fileInputName1']['error'] === UPLOAD_ERR_OK)
{
  $fileTmpPath = $_FILES['fileInputName1']['tmp_name'];
  $fileName = $_FILES['fileInputName1']['name'];

  move_uploaded_file($fileTmpPath, '/the/final/path/you/want/' . $fileName);
}

我希望你覺得它有用,我很關注你的問題。

這是帶有基本身份驗證 C# 的多部分數據帖子

public string UploadFilesToRemoteUrl(string url)
    {
        try
        {                             

            Dictionary<string, object> formFields = new Dictionary<string, object>();
            formFields.Add("requestid", "{\"id\":\"idvalue\"}");

            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "multipart/form-data; boundary=" + boundary;

            // basic authentication.
            var username = "userid";
            var password = "password";

            string credidentials = username + ":" + password;
            var authorization = Convert.ToBase64String(Encoding.Default.GetBytes(credidentials));
            request.Headers["Authorization"] = "Basic " + authorization;

            request.Method = "POST";
            request.KeepAlive = true;

            Stream memStream = new System.IO.MemoryStream();
            WriteFormData(formFields, memStream, boundary);

            FileInfo fileToUpload = new FileInfo(@"filelocation with name");
            string fileFormKey = "file";
            if (fileToUpload != null)
            {
                WritefileToUpload(fileToUpload, memStream, boundary, fileFormKey);
            }
            request.ContentLength = memStream.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                memStream.Position = 0;
                byte[] tempBuffer = new byte[memStream.Length];
                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                memStream.Close();
                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            }

            using (var response = request.GetResponse())
            {
                Stream responseSReam = response.GetResponseStream();
                StreamReader streamReader = new StreamReader(responseSReam);
                return streamReader.ReadToEnd();
            }
        }
        catch (WebException ex)
        {
            using (WebResponse response = ex.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse)response;
                using (var streamReader = new StreamReader(response.GetResponseStream()))
                    return streamReader.ReadToEnd();

            }
        }
    }

    // write form id.
    public static void WriteFormData(Dictionary<string, object> dictionary, Stream stream, string mimeBoundary)
    {
        string formdataTemplate = "\r\n--" + mimeBoundary +
                                    "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
        if (dictionary != null)
        {
            foreach (string key in dictionary.Keys)
            {
                string formitem = string.Format(formdataTemplate, key, dictionary[key]);
                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                stream.Write(formitembytes, 0, formitembytes.Length);
            }
        }
    }

    // write file.
    public static void WritefileToUpload(FileInfo file, Stream stream, string mimeBoundary, string formkey)
    {
        var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + mimeBoundary + "\r\n");
        var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + mimeBoundary + "--");

        string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                                "Content-Type: application/octet-stream\r\n\r\n";

        stream.Write(boundarybytes, 0, boundarybytes.Length);
        var header = string.Format(headerTemplate, formkey, file.Name);
        var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

        stream.Write(headerbytes, 0, headerbytes.Length);

        using (var fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
        {
            var buffer = new byte[1024];
            var bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                stream.Write(buffer, 0, bytesRead);
            }
        }
        stream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
    } 

我知道這是一個舊帖子,但在花了整個下午的時間嘗試之后,我必須分享對我有用的東西。 我的解決方案適用於 Xamarin 應用程序,但只要它是 C#,代碼就應該仍然有效:

我遇到的問題是我想使用與我的 Angular 應用程序相同的端點和負載。 (下面的代碼)。

    public class ApiService<T> where T : class
    {
        private string _webServiceUrl = Settings.WebServiceUrl;
        private HttpClient httpClient;

        public ApiService(string path = null)
        {
            _webServiceUrl = $"{_webServiceUrl}{path}/";

            httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri(_webServiceUrl);
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Settings.Token);
        }

        private void HandleException(Exception ex, string url = "")
        {
            Settings.TotalHttpRequests -= 1;

            Crashes.TrackError(ex, new Dictionary<string, string>{ { "URL", url }, });

            MessagingCenter.Send<Page, string>(new Page(), "Exception", ex.Message);

        }

        public async Task<T> PostFormDataAsync(string url, string filePath, T t)
        {
            using (var form = new MultipartFormDataContent())
            {
                using (var fs = File.OpenRead(filePath))
                {
                    byte[] bytes = new byte[fs.Length];

                    fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
                    fs.Close();

                    var json = JsonConvert.SerializeObject(t);
                    var data = new StringContent(json);

                    form.Add(new ByteArrayContent(bytes, 0, bytes.Length), "file", fs.Name);
                    form.Add(data, "data");

                    Settings.TotalHttpRequests += 1;

                    var result = await httpClient.PostAsync(url, form);

                    Settings.TotalHttpRequests -= 1;

                    if (result.IsSuccessStatusCode)
                    {
                        var content = await result.Content.ReadAsStringAsync();
                        var item = JsonConvert.DeserializeObject<T>(content);

                        return item;
                    }
                    else
                    {
                        await RaiseErrorAsync(result);

                        return default(T);
                    }
                }
            }
        }

        private async Task RaiseErrorAsync(HttpResponseMessage result)
        {
            var message = await result.Content.ReadAsStringAsync();

            MessagingCenter.Send<Page, string>(new Page(), "Error", message);
        }
    }

為了其他 Xamarin 開發人員的利益,我包含了一些代碼。

我的 API 端點如下:

        [DisableRequestSizeLimit]
        [Consumes("multipart/form-data")]
        [HttpPost]
        public async Task<ActionResult> Post()
        {
            try
            {
                var data = (Request.Form["data"]).ToString();
                var myObject = JsonConvert.DeserializeObject<MyClass>(data);
                var file = Request.Form.Files[0];
                
                myObject = await _service.AddAsync(myObject, file);

                var result = _mapper.Map<MyClassDto>(myObject);

                return Ok(result);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }

        }

由此,我將文件作為 IFormFile 實例獲取。 我還能夠反序列化我作為t類型的T發送的 object。

可以修改 ApiService 以實現 IApiService,以便您可以從依賴服務(在 Xamarin 中)中受益。

在 Angular 方面,這是我在組件上的內容:

  onSubmit() {
    this.submitted = true;
    
    if (this.form.invalid) {return;}

    if (this.fileToUpload == null) {
      Swal.fire('File', 'Please attach the file', 'error');
      return;
    }

    const formData = new FormData();
    formData.append('file', this.fileToUpload, this.fileToUpload.name);
    formData.append('data', JSON.stringify(this.form.value));

    this.service.postEndpoint('', formData).subscribe((data) => {
      //Do something here
    });
  }

對於服務:

import { ApiService } from '../api.service';

@Injectable({
  providedIn: 'root'
})
export class MyService extends ApiService<MyClass>{

  constructor(protected httpClient: HttpClient) {
    super(httpClient, 'MyApiController');
  }
}

服務:

const httpOptions = {
  headers : new HttpHeaders({
    Authorization: 'Bearer ' + localStorage.getItem('token')
  })
};

export abstract class ApiService<T> {
  basePath = environment.apiPath;
  apiURL = `${this.basePath}api/`;

  constructor(protected httpClient: HttpClient, protected actionUrl: string) { }

  public postEndpoint(endPoint: string, model: any): Observable<any> {
    return this.httpClient.post(this.apiURL + `${this.actionUrl}/${endPoint}`, model, httpOptions);
  }
}

我希望這可以節省一些時間! 編碼愉快!

它適用於窗口電話 8.1。 你可以試試這個。

Dictionary<string, object> _headerContents = new Dictionary<string, object>();
const String _lineEnd = "\r\n";
const String _twoHyphens = "--";
const String _boundary = "*****";
private async void UploadFile_OnTap(object sender, System.Windows.Input.GestureEventArgs e)
{
   Uri serverUri = new Uri("http:www.myserver.com/Mp4UploadHandler", UriKind.Absolute);    
   string fileContentType = "multipart/form-data";       
   byte[] _boundarybytes = Encoding.UTF8.GetBytes(_twoHyphens + _boundary + _lineEnd);
   byte[] _trailerbytes = Encoding.UTF8.GetBytes(_twoHyphens + _boundary + _twoHyphens + _lineEnd);
   Dictionary<string, object> _headerContents = new Dictionary<string, object>();
   SetEndHeaders();  // to add some extra parameter if you need

   httpWebRequest = (HttpWebRequest)WebRequest.Create(serverUri);
   httpWebRequest.ContentType = fileContentType + "; boundary=" + _boundary;
   httpWebRequest.Method = "POST";
   httpWebRequest.AllowWriteStreamBuffering = false;  // get response after upload header part

   var fileName = Path.GetFileName(MediaStorageFile.Path);    
   Stream fStream = (await MediaStorageFile.OpenAsync(Windows.Storage.FileAccessMode.Read)).AsStream(); //MediaStorageFile is a storage file from where you want to upload the file of your device    
   string fileheaderTemplate = "Content-Disposition: form-data; name=\"{0}\"" + _lineEnd + _lineEnd + "{1}" + _lineEnd;    
   long httpLength = 0;
   foreach (var headerContent in _headerContents) // get the length of upload strem
   httpLength += _boundarybytes.Length + Encoding.UTF8.GetBytes(string.Format(fileheaderTemplate, headerContent.Key, headerContent.Value)).Length;

   httpLength += _boundarybytes.Length + Encoding.UTF8.GetBytes("Content-Disposition: form-data; name=\"uploadedFile\";filename=\"" + fileName + "\"" + _lineEnd).Length
                                       + Encoding.UTF8.GetBytes(_lineEnd).Length * 2 + _trailerbytes.Length;
   httpWebRequest.ContentLength = httpLength + fStream.Length;  // wait until you upload your total stream 

    httpWebRequest.BeginGetRequestStream((result) =>
    {
       try
       {
         HttpWebRequest request = (HttpWebRequest)result.AsyncState;
         using (Stream stream = request.EndGetRequestStream(result))
         {
            foreach (var headerContent in _headerContents)
            {
               WriteToStream(stream, _boundarybytes);
               WriteToStream(stream, string.Format(fileheaderTemplate, headerContent.Key, headerContent.Value));
             }

             WriteToStream(stream, _boundarybytes);
             WriteToStream(stream, "Content-Disposition: form-data; name=\"uploadedFile\";filename=\"" + fileName + "\"" + _lineEnd);
             WriteToStream(stream, _lineEnd);

             int bytesRead = 0;
             byte[] buffer = new byte[2048];  //upload 2K each time

             while ((bytesRead = fStream.Read(buffer, 0, buffer.Length)) != 0)
             {
               stream.Write(buffer, 0, bytesRead);
               Array.Clear(buffer, 0, 2048); // Clear the array.
              }

              WriteToStream(stream, _lineEnd);
              WriteToStream(stream, _trailerbytes);
              fStream.Close();
         }
         request.BeginGetResponse(a =>
         { //get response here
            try
            {
               var response = request.EndGetResponse(a);
               using (Stream streamResponse = response.GetResponseStream())
               using (var memoryStream = new MemoryStream())
               {   
                   streamResponse.CopyTo(memoryStream);
                   responseBytes = memoryStream.ToArray();  // here I get byte response from server. you can change depends on server response
               }    
              if (responseBytes.Length > 0 && responseBytes[0] == 1)
                 MessageBox.Show("Uploading Completed");
              else
                  MessageBox.Show("Uploading failed, please try again.");
            }
            catch (Exception ex)
            {}
          }, null);
      }
      catch (Exception ex)
      {
         fStream.Close();                             
      }
   }, httpWebRequest);
}

private static void WriteToStream(Stream s, string txt)
{
   byte[] bytes = Encoding.UTF8.GetBytes(txt);
   s.Write(bytes, 0, bytes.Length);
 }

 private static void WriteToStream(Stream s, byte[] bytes)
 {
   s.Write(bytes, 0, bytes.Length);
 }

 private void SetEndHeaders()
 {
   _headerContents.Add("sId", LocalData.currentUser.SessionId);
   _headerContents.Add("uId", LocalData.currentUser.UserIdentity);
   _headerContents.Add("authServer", LocalData.currentUser.AuthServerIP);
   _headerContents.Add("comPort", LocalData.currentUser.ComPort);
 }

對於在嘗試以多部分形式上傳時搜索 403 禁止問題的人來說,以下可能會有所幫助,因為根據服務器配置,由於 MultipartFormDataContent 標頭不正確,您將收到 MULTIPART_STRICT_ERROR "!@eq 0" 的情況。 請注意,兩個 imagetag/filename 變量都包含引號 (\\"),例如 filename="\\"myfile.png\\"" 。

    MultipartFormDataContent form = new MultipartFormDataContent();
    ByteArrayContent imageContent = new ByteArrayContent(fileBytes, 0, fileBytes.Length);
    imageContent.Headers.TryAddWithoutValidation("Content-Disposition", "form-data; name="+imagetag+"; filename="+filename);
    imageContent.Headers.TryAddWithoutValidation("Content-Type", "image / png");
    form.Add(imageContent, imagetag, filename);

我還想將內容上傳到服務器,這是一個 Spring 應用程序,我最終發現我需要實際設置內容類型以將其解釋為文件。 像這樣:

...
MultipartFormDataContent form = new MultipartFormDataContent();
var fileStream = new FileStream(uniqueTempPathInProject, FileMode.Open);
var streamContent = new StreamContent(fileStream);
streamContent.Headers.ContentType=new MediaTypeHeaderValue("application/zip");
form.Add(streamContent, "file",fileName);
...

頂到@loop 答案。

我們收到以下 Asp.Net MVC 錯誤,無法連接到遠程服務器

修復:在 Web.Confing 中添加以下代碼后問題已為我們解決

  <system.net>
    <defaultProxy useDefaultCredentials="true" >
    </defaultProxy>
  </system.net>

基於@Wolf5 的回答這對我有用

var client = new WebClient();
client.Encoding = Encoding.UTF8;
var boundary = $"--------------------------{DateTime.Now.Ticks:x}";
client.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
client.Headers.Add("Cookie", cookie); 

var start = $"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{Path.GetFileName(fileName)}\"\r\nContent-Type: image/jpeg\r\n\r\n";
var end = $"\r\n--{boundary}--\r\n";

var lst = new List<byte>();
lst.AddRange(client.Encoding.GetBytes(start));
lst.AddRange(File.ReadAllBytes(fileName));
lst.AddRange(client.Encoding.GetBytes(end));

var resp = client.UploadData($"{ApiUrl}/api/upload/image", "POST", lst.ToArray());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM