问题描述
我有一个 C/S 应用程序.我用 Asp.Net MVC 4.0 实现了服务器,而客户端在 .Net 4.5 上运行.
I have a C/S application. I implemented the server with Asp.Net MVC 4.0, and the client runs on .Net 4.5.
我在服务器端有一个控制器动作如下所示:
I have a Controller Action in the server side looks like this:
public JsonResult Upload(string arg1, int arg2)
{
//do something about arg1 and arg2 here
...
var files = Request.Files;
if (files.Count > 0)
{
foreach(var file in files)
{
var ms = new MemoryStream();
file.InputStream.CopyTo(ms);
//save it to somewhere
...
}
}
...
}
我创建了一个测试 html 页面以在浏览器中对其进行测试.它按预期工作.
I created a test html page to test it in browser. It worked as expected.
在客户端,我使用 HttpClient 类,它在不涉及文件上传的情况下完美运行.然而,经过几天的研究,我仍然没有运气在我运行 IIS Express 的调试机器中解决这个问题.发现所有的线索都指向MultipartFormDataContent
,但是还是不行,即使我复制了那些示例代码,服务器端还是拿不到东西,所有的args都为空,并且Request.Files
中没有文件.我曾经拥有基于 HttpWebRequest,它适用于文件上传,但我更喜欢在这个新项目中使用 HttpClient.
In the client side, I use HttpClient class and it worked perfectly where no file uploading involved. However after days of researching I still have no luck to resolve this in my debug machine which runs IIS Express. I found that all clues leads to MultipartFormDataContent
, but still can't get it work, even if I copy those sample codes, the server side still can't get a thing, all args are empty, and no files is there in the Request.Files
. I used to have my own http helper class based on HttpWebRequest, which works for file uploading, but I prefer to use HttpClient in this new project.
那么,如何使用 HttpClient 将文件上传到服务器?
So, How do I upload files to the server with HttpClient?
推荐答案
用 Fiddler 调试后,对比了原始的 http 消息和 WinMerge,我发现了 Firefox 和我的程序的区别:
After debugging with Fiddler, comparing raw http message with WinMerge, I found the differences between Firefox and my program:
Firefox(删除了一些标题以使事情变得简单):
POST http://localhost:53400/Input/Upload HTTP/1.1
Host: localhost:53400
Content-Type: multipart/form-data; boundary=---------------------------1590871622043
Content-Length: ****
-----------------------------1590871622043
Content-Disposition: form-data; name="arg1"
abc
-----------------------------1590871622043
Content-Disposition: form-data; name="arg2"
3
-----------------------------1590871622043
Content-Disposition: form-data; name="uploadfile"; filename="wave.wav"
Content-Type: audio/wav
//file data here
-----------------------------1590871622043--
我的带有 MultipartFormDataContent
的程序:
My Program with MultipartFormDataContent
:
POST http://localhost:53400/Input/Save HTTP/1.1
Content-Type: multipart/form-data; boundary="caac5ea7-8ab4-4682-be40-ecb3ddf3e70a"
Host: localhost:53400
Content-Length: ****
--caac5ea7-8ab4-4682-be40-ecb3ddf3e70a
Content-Disposition: form-data; name=arg1
abc
--caac5ea7-8ab4-4682-be40-ecb3ddf3e70a
Content-Disposition: form-data; name=arg2
3
--caac5ea7-8ab4-4682-be40-ecb3ddf3e70a
Content-Disposition: form-data; name=uploadfile; filename=wave.wav; filename*=utf-8''wave.wav
//file data here
--caac5ea7-8ab4-4682-be40-ecb3ddf3e70a--
我注意到的最后一件事是,在这些 Content-Disposition
行中,Firefox 引用了所有值,但我的程序没有引用.人们很容易认为这无关紧要,但最终我发现这才是真正的原因.
The last thing I would notice is that in these Content-Disposition
lines, Firefox quotes all values, but my program does not. One could easily assume that it would not matter, but in the end, I found that is the exact cause.
现在我知道原因了,下面是有效的代码,就像引用名称一样简单:
Now that I know the reason, here comes the code that works, as easy as quoting the names:
var multipart = new MultipartFormDataContent();
multipart.Add(new StringContent("abc"), '"' + "arg1" + '"');
multipart.Add(new StringContent("3"), '"' + "arg2" + '"');
// byte[] fileData;
multipart.Add(new ByteArrayContent(fileData), '"' + "uploadfile"+ '"', '"' + "wave.wav" + '"');
//HttpClient http; string url;
var response = await http.PostAsync(url, multipart);
response.EnsureSuccessStatusCode();
//...
这篇关于如何使用 .Net 4.0 中包含的 HttpClient 类将文件上传到在 IIS Express 中运行的 Asp.Net MVC 4.0 操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!