Http MultipartFormDataContent

33

我被要求使用C#完成以下任务:

/**

* 1. Create a MultipartPostMethod

* 2. Construct the web URL to connect to the SDP Server

* 3. Add the filename to be attached as a parameter to the MultipartPostMethod with parameter name "filename"

* 4. Execute the MultipartPostMethod

* 5. Receive and process the response as required

* /

我写了一些没有错误的代码,但是文件没有被附加。

能否有人看看我的C#代码,看看是否我写错了代码?

这是我的代码:

var client = new HttpClient();
const string weblinkUrl = "http://testserver.com/attach?";
var method = new MultipartFormDataContent();
const string fileName = "C:\file.txt";
var streamContent = new StreamContent(File.Open(fileName, FileMode.Open));
method.Add(streamContent, "filename");

var result = client.PostAsync(weblinkUrl, method);
MessageBox.Show(result.Result.ToString());

1
这个问题在SO上已经被问了很多次。以下是一些可能的解决方案:C# HttpClient 4.5 multipart/form-data上传:https://dev59.com/oGQn5IYBdhLWcg3w_LNH C#中的HttpClient Multipart Form Post:https://dev59.com/Z2Ml5IYBdhLWcg3w3aLj 就个人而言,请检查请求中发送的帖子数据,并检查响应。 [Fiddler](http://fiddler2.com/)非常出色。 - Torra
5个回答

35

在C#中发布MultipartFormDataContent很简单,但第一次可能会让人感到困惑。以下是我用于发布.png、.txt等文件的代码。

// 2. Create the url 
string url = "https://myurl.com/api/...";
string filename = "myFile.png";
// In my case this is the JSON that will be returned from the post
string result = "";
// 1. Create a MultipartPostMethod
// "NKdKd9Yk" is the boundary parameter

using (var formContent = new MultipartFormDataContent("NKdKd9Yk"))
{
    formContent.Headers.ContentType.MediaType = "multipart/form-data";
    // 3. Add the filename C:\\... + fileName is the path your file
    Stream fileStream = System.IO.File.OpenRead("C:\\Users\\username\\Pictures\\" + fileName);
    formContent.Add(new StreamContent(fileStream), fileName, fileName);

    using (var client = new HttpClient())
    {
        // Bearer Token header if needed
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _bearerToken);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/form-data"));

        try
        {
            // 4.. Execute the MultipartPostMethod
            var message = await client.PostAsync(url, formContent);
            // 5.a Receive the response
            result = await message.Content.ReadAsStringAsync();                
        }
        catch (Exception ex)
        {
            // Do what you want if it fails.
            throw ex;
        }
    }    
}

// 5.b Process the reponse Get a usable object from the JSON that is returned
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(result);

在我的情况下,我需要在对象发布后对其进行某些操作,因此我使用JsonConvert将其转换为该对象。


2
content是什么?和formContent一样吗? - dube
1
@dube 是的,当我写答案时,我失误了,把 content 写成了 formContent。我已经更正了。感谢你指出。 - Braden Brown

2

请指定第三个参数,即fileName

像这样:

method.Add(streamContent, "filename", "filename.pdf");

当前您的回答写得不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答问题。您可以在帮助中心找到有关撰写良好答案的更多信息。 - Community
1
对我来说似乎很清楚。 - TheLegendaryCopyCoder

2

我知道这是一篇旧文章,但对于那些正在寻找解决方案的人,为了提供更直接的答案,以下是我发现的:

using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

public class UploadController : ApiController
{
    public async Task<HttpResponseMessage> PostFormData()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        try
        {
            // Read the form data.
            await Request.Content.ReadAsMultipartAsync(provider);

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);
            }

            return Request.CreateResponse(HttpStatusCode.OK);
        }
        catch (System.Exception e)
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
        }
    }
}

这是我找到的地方: http://www.asp.net/web-api/overview/advanced/sending-html-form-data,-part-2 更详细的实现方法请参考: http://galratner.com/blogs/net/archive/2013/03/22/using-html-5-and-the-web-api-for-ajax-file-uploads-with-image-preview-and-a-progress-bar.aspx

13
这个程序“读取”multipart/form-data,而不是“发送”它。我想知道你是否看了这个问题,因为它甚至没有涉及ASP.NET Web API。 - Camilo Terevinto
这是服务器端代码。OP要求客户端代码发送请求。 - Mostafa Zeinali
@SOusedtobegood 我知道这条评论有点老了,但我有一段时间没有登录了。嗯,问题中提到了C#,所以.NET是隐含的,而那段代码不是来自ASP,而是来自我正在开发的MVC项目。O_o - iuppiter
@MostafaZeinali 兄弟,你什么时候见过C#客户端?在发表评论之前,你真的得先读问题。问题明确说明“有人能否看一下我的C#代码,看看我是否编写了错误的代码?” o_O - iuppiter
3
我曾经多次见过使用C#编写的客户端应用程序,任何想要与服务器发送/接收数据的客户端C#应用程序都需要编写客户端代码。在作者的问题中,我还看到了一次,"client.PostAsync(weblinkUrl, method);" 这是一个客户端代码,试图向服务器发送一个POST请求。简单明了。另一方面,您的代码是一个服务器端代码,它接收多部分POST请求并从中“读取”附加的文件。您和作者可以一起创建Web应用程序,您负责服务器端,作者负责客户端。 - Mostafa Zeinali
链接已经失效。 - Gert Arnold

1

我调试了一下,问题出在这里:

method.Add(streamContent, "filename");

这个“添加”实际上并没有将文件放在多部分内容的正文中。


0

我知道这是老问题,但我只想给出一个更清晰的例子。变量image是一个byte[],而filename是一个包含图像名称的字符串:

        ByteArrayContent imageContent = new ByteArrayContent(image);
        imageContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

        MultipartFormDataContent formData = new MultipartFormDataContent();        
        pFormData.Add(imageContent, "image", fileName);
        
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "destinatioUri");
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Content = formData;
            
        HttpResponseMessage response = await _httpClient.SendAsync(request);            

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接