通过 WebClient 使用 POST 值上传文件
Posted
技术标签:
【中文标题】通过 WebClient 使用 POST 值上传文件【英文标题】:UploadFile with POST values by WebClient 【发布时间】:2012-06-18 09:08:44 【问题描述】:我想使用 WebClient 类将文件上传到主机。我还想传递一些值,这些值应该显示在服务器部分(php)的 $_POST 数组中。我想一键搞定
我使用了下面的代码
using (WebClient wc = new WebClient())
wc.Encoding = Encoding.UTF8;
NameValueCollection values = new NameValueCollection();
values.Add("client", "VIP");
values.Add("name", "John Doe");
wc.QueryString = values; // this displayes in $_GET
byte[] ans= wc.UploadFile(address, dumpPath);
如果我使用了 QueryString 属性,则显示在 $_GET 数组中的值。但我想通过 post 方法发送它
【问题讨论】:
类似问题***.com/questions/2950292/…你可能想检查答案 【参考方案1】:没有任何内置功能可以让您这样做。我有blogged 关于您可以使用的扩展名。以下是相关类:
public class UploadFile
public UploadFile()
ContentType = "application/octet-stream";
public string Name get; set;
public string Filename get; set;
public string ContentType get; set;
public Stream Stream get; set;
public byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values)
var request = WebRequest.Create(address);
request.Method = "POST";
var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
request.ContentType = "multipart/form-data; boundary=" + boundary;
boundary = "--" + boundary;
using (var requestStream = request.GetRequestStream())
// Write the values
foreach (string name in values.Keys)
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"0\"11", name, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
// Write the files
foreach (var file in files)
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"0\"; filename=\"1\"2", file.Name, file.Filename, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: 011", file.ContentType, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
file.Stream.CopyTo(requestStream);
buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
using (var response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var stream = new MemoryStream())
responseStream.CopyTo(stream);
return stream.ToArray();
现在你可以在你的应用程序中使用它了:
using (var stream = File.Open(dumpPath, FileMode.Open))
var files = new[]
new UploadFile
Name = "file",
Filename = Path.GetFileName(dumpPath),
ContentType = "text/plain",
Stream = stream
;
var values = new NameValueCollection
"client", "VIP" ,
"name", "John Doe" ,
;
byte[] result = UploadFiles(address, files, values);
现在您可以在您的 PHP 脚本中使用 $_POST["client"]
、$_POST["name"]
和 $_FILES["file"]
。
【讨论】:
有哪些步骤可以使这个异步与进度指示同步? HttpWebClient 上的同步函数应该替换为它们的异步对应函数:Begin/EndGetRequestStream、Begin/EndGetResponse、... 感谢您提供此代码!如果您使用的是 MVC 4,您可能会遇到以下异常:' MIME 多部分流的意外结束。 MIME 多部分消息不完整。框架内部存在错误(aspnetwebstack.codeplex.com/discussions/354215),您需要在最后一个边界处添加一个新行: var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--" + Environment.NewLine); 如果有人想在 Mono (linux/Mac) 上运行它,您可能需要更改Environment.Newline
以明确使用 \r\n
,因为 on those platforms Environment.Newline
will return \n
和 RFC 1867 第 5.9 节指定这应该始终是CRLF
。虽然没有测试过这个。感谢您填补了 Web API 中的巨大空白,@Darin
我收到了 400 Bad Request,因为在 http 内容的末尾缺少一个额外的 NewLine。哈哈【参考方案2】:
如果有人想以异步模式使用 @darin-dimitrov 的解决方案并提供进度报告,那就是可行的方法(对于 .NET 4.0):
public void UploadFileAsync(NameValueCollection values, Stream fileStream)
//to fire events on the calling thread
_asyncOperation = AsyncOperationManager.CreateOperation(null);
var ms = new MemoryStream();
//make a copy of the input stream in case sb uses disposable stream
fileStream.CopyTo(ms);
//you cannot set stream position often enough to zero
ms.Position = 0;
Task.Factory.StartNew(() =>
try
const string contentType = "application/octet-stream";
var request = WebRequest.Create(_url);
request.Method = "POST";
var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
request.ContentType = "multipart/form-data; boundary=" + boundary;
boundary = "--" + boundary;
var dataStream = new MemoryStream();
byte[] buffer;
// Write the values
foreach (string name in values.Keys)
buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
dataStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"0\"11", name, Environment.NewLine));
dataStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
dataStream.Write(buffer, 0, buffer.Length);
// Write the file
buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
dataStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"file\"; filename=\"file\"Environment.NewLine");
dataStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: 011", contentType, Environment.NewLine));
dataStream.Write(buffer, 0, buffer.Length);
ms.CopyTo(dataStream);
buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
dataStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(boundary + "--");
dataStream.Write(buffer, 0, buffer.Length);
dataStream.Position = 0;
//IMPORTANT: set content length to directly write to network socket
request.ContentLength = dataStream.Length;
var requestStream = request.GetRequestStream();
//Write data in chunks and report progress
var size = dataStream.Length;
const int chunkSize = 64 * 1024;
buffer = new byte[chunkSize];
long bytesSent = 0;
int readBytes;
while ((readBytes = dataStream.Read(buffer, 0, buffer.Length)) > 0)
requestStream.Write(buffer, 0, readBytes);
bytesSent += readBytes;
var status = "Uploading... " + bytesSent / 1024 + "KB of " + size / 1024 + "KB";
var percentage = Tools.Clamp(Convert.ToInt32(100 * bytesSent / size), 0, 100);
OnFileUploaderProgressChanged(new FileUploaderProgessChangedEventArgs(status, percentage));
//get response
using (var response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var stream = new MemoryStream())
// ReSharper disable once PossibleNullReferenceException - exception would get catched anyway
responseStream.CopyTo(stream);
var result = Encoding.Default.GetString(stream.ToArray());
OnFileUploaderCompleted(result == string.Empty
? new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Failed)
: new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Ok));
catch (Exception)
OnFileUploaderCompleted(new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Failed));
, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
【讨论】:
嗨,感谢您的代码,我正在尝试在我的项目中实现它,但我对此部分有一些疑问: OnFileUploaderCompleted(result == string.Empty ? new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Failed) : 新的 FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Ok));我如何声明“FileUploaderCompletedResult”?以上是关于通过 WebClient 使用 POST 值上传文件的主要内容,如果未能解决你的问题,请参考以下文章
用webclient下载网页,需要post方式传值,可为啥通过uploadvalues函数下载不成功