ASP.NET WebApi:如何使用WebApi HttpClient执行带文件上传的多部分POST请求

67

我有一个WebApi服务处理来自简单表单的上传,就像这个表单:

    <form action="/api/workitems" enctype="multipart/form-data" method="post">
        <input type="hidden" name="type" value="ExtractText" />
        <input type="file" name="FileForUpload" />
        <input type="submit" value="Run test" />
    </form>

然而,我无法弄清如何使用HttpClient API模拟相同的帖子。 FormUrlEncodedContent 部分相当简单,但是我该如何将文件内容与名称添加到帖子中呢?


1
你介意分享在WebApi端消费MultipartFormDataContent的代码吗? - granadaCoder
示例:将参数作为多部分发送,.NET 3.0 中的答案。 - D.Oleg
3个回答

134

经过多次尝试和错误,这里是实际可行的代码:

using (var client = new HttpClient())
{
    using (var content = new MultipartFormDataContent())
    {
        var values = new[]
        {
            new KeyValuePair<string, string>("Foo", "Bar"),
            new KeyValuePair<string, string>("More", "Less"),
        };

        foreach (var keyValuePair in values)
        {
            content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
        }

        var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));
        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = "Foo.txt"
        };
        content.Add(fileContent);

        var requestUri = "/api/action";
        var result = client.PostAsync(requestUri, content).Result;
    }
}

23
使用 StreamContent 处理大文件: var fileContent = new StreamContent(File.OpenRead(fileName)); - Jalal El-Shaer
3
奇怪的是这对我不起作用。我不得不在内容名称周围添加引号,看见这个:http://stackoverflow.com/questions/15638622/how-to-upload-files-to-asp-net-mvc-4-0-action-running-in-iis-express-with-httpcl/15638623#15638623 - deerchao
6
了解,System.Net.Mime.DispositionTypeNames 中有一个 "attachment" 常量用于附件。 - Robert
2
我也不得不在名称值周围添加引号:FileName = ""TestImage.jpg"". 我在服务器上使用的是ServiceStack而不是WebAPI,不确定是否相关。 - Rob Bird
我一直收到“StatusCode: 415,ReasonPhrase:'Unsupported Media Type'”的错误信息,你有什么想法吗? - djack109
显示剩余2条评论

14

感谢 @Michael Tepper 的回答。

我不得不向 MailGun(电子邮件提供商)发布附件,而且我必须稍微修改它,以便它能够接受我的附件。

var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));
fileContent.Headers.ContentDisposition = 
        new ContentDispositionHeaderValue("form-data") //<- 'form-data' instead of 'attachment'
{
    Name = "attachment", // <- included line...
    FileName = "Foo.txt",
};
multipartFormDataContent.Add(fileContent);

作为参考,感谢。


11

你需要查找各种HttpContent的子类。

你创建一个多部分的http内容并向其中添加各种部分。在你的情况下,你有一个字节数组内容和表单url编码类似于

HttpClient c = new HttpClient();
var fileContent = new ByteArrayContent(new byte[100]);
fileContent.Headers.ContentDisposition 
  = new ContentDispositionHeaderValue("attachment")
{
  FileName = "myFilename.txt"
};

var formData = new FormUrlEncodedContent(new[]
{
  new KeyValuePair<string, string>("name", "ali"),
  new KeyValuePair<string, string>("title", "ostad")
}); 
        
MultipartContent content = new MultipartContent();
content.Add(formData);
content.Add(fileContent);
c.PostAsync(myUrl, content);

1
不幸的是,那样做行不通,尽管 ContentDisposition 标头似乎让我向前迈了一步。如果我按原样使用您的示例代码,会出现 Unsupported Media Type 异常。但是,如果我将 MultipartContent 替换为 MultipartFormDataContent,异常就消失了。然而,在服务器上,隐藏字段的值确实丢失了。 - Michael Teper
@MichaelTeper 我还没有测试这段代码。我会稍微尝试一下并更新帖子,但我的重点是向您展示需要寻找的代码片段,而不是可工作的代码。 - Aliostad
我刚刚收到了 StatusCode: 415, ReasonPhrase: '不支持的媒体类型' 的错误信息。 - djack109

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