是否有任何类,库或一些代码片段,将帮助我上传文件与HTTPWebrequest?
编辑2:
我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。
编辑:
WebClient不覆盖我的需求,所以我正在寻找一个解决方案与HTTPWebrequest。
是否有任何类,库或一些代码片段,将帮助我上传文件与HTTPWebrequest?
编辑2:
我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。
编辑:
WebClient不覆盖我的需求,所以我正在寻找一个解决方案与HTTPWebrequest。
当前回答
我最近不得不处理这个问题——另一种方法是使用WebClient是可继承的这一事实,并从那里改变底层的WebRequest:
http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest (VS.80) . aspx
我更喜欢c#,但如果你坚持使用VB,结果将是这样的:
Public Class BigWebClient
Inherits WebClient
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim x As WebRequest = MyBase.GetWebRequest(address)
x.Timeout = 60 * 60 * 1000
Return x
End Function
End Class
'Use BigWebClient here instead of WebClient
其他回答
我最近不得不处理这个问题——另一种方法是使用WebClient是可继承的这一事实,并从那里改变底层的WebRequest:
http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest (VS.80) . aspx
我更喜欢c#,但如果你坚持使用VB,结果将是这样的:
Public Class BigWebClient
Inherits WebClient
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim x As WebRequest = MyBase.GetWebRequest(address)
x.Timeout = 60 * 60 * 1000
Return x
End Function
End Class
'Use BigWebClient here instead of WebClient
这不需要外部代码、扩展和“低级”HTTP操作(只需要NuGet中的Microsoft.Net.Http包)。这里有一个例子:
// Perform the equivalent of posting a form with a filename and two files, in HTML:
// <form action="{url}" method="post" enctype="multipart/form-data">
// <input type="text" name="filename" />
// <input type="file" name="file1" />
// <input type="file" name="file2" />
// </form>
private async Task<System.IO.Stream> UploadAsync(string url, string filename, Stream fileStream, byte [] fileBytes)
{
// Convert each of the three inputs into HttpContent objects
HttpContent stringContent = new StringContent(filename);
// examples of converting both Stream and byte [] to HttpContent objects
// representing input type file
HttpContent fileStreamContent = new StreamContent(fileStream);
HttpContent bytesContent = new ByteArrayContent(fileBytes);
// Submit the form using HttpClient and
// create form data as Multipart (enctype="multipart/form-data")
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
// Add the HttpContent objects to the form data
// <input type="text" name="filename" />
formData.Add(stringContent, "filename", "filename");
// <input type="file" name="file1" />
formData.Add(fileStreamContent, "file1", "file1");
// <input type="file" name="file2" />
formData.Add(bytesContent, "file2", "file2");
// Invoke the request to the server
// equivalent to pressing the submit button on
// a form with attributes (action="{url}" method="post")
var response = await client.PostAsync(url, formData);
// ensure the request was a success
if (!response.IsSuccessStatusCode)
{
return null;
}
return await response.Content.ReadAsStreamAsync();
}
}
采用上面的代码并修复,因为它抛出内部服务器错误500。\r\n的位置和空格等存在一些问题。应用内存流重构,直接写入请求流。结果如下:
public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc) {
log.Debug(string.Format("Uploading {0} to {1}", file, url));
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
foreach (string key in nvc.Keys)
{
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, file, 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);
log.Debug(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
} catch(Exception ex) {
log.Error("Error uploading file", ex);
if(wresp != null) {
wresp.Close();
wresp = null;
}
} finally {
wr = null;
}
}
以及示例用法:
NameValueCollection nvc = new NameValueCollection();
nvc.Add("id", "TTR");
nvc.Add("btn-submit-photo", "Upload");
HttpUploadFile("http://your.server.com/upload",
@"C:\test\test.jpg", "file", "image/jpeg", nvc);
可以扩展它来处理多个文件,或者对每个文件多次调用它。但它适合你的需要。
查看MyToolkit库:
var request = new HttpPostRequest("http://www.server.com");
request.Data.Add("name", "value"); // POST data
request.Files.Add(new HttpPostFile("name", "file.jpg", "path/to/file.jpg"));
await Http.PostAsync(request, OnRequestFinished);
http://mytoolkit.codeplex.com/wikipage?title=Http
基于上面提供的代码,我添加了对多个文件的支持,也可以直接上传流,而不需要有本地文件。
要将文件上传到包含一些post参数的特定url,请执行以下操作:
RequestHelper.PostMultipart(
"http://www.myserver.com/upload.php",
new Dictionary<string, object>() {
{ "testparam", "my value" },
{ "file", new FormFile() { Name = "image.jpg", ContentType = "image/jpeg", FilePath = "c:\\temp\\myniceimage.jpg" } },
{ "other_file", new FormFile() { Name = "image2.jpg", ContentType = "image/jpeg", Stream = imageDataStream } },
});
为了进一步增强这一点,可以从给定的文件本身确定名称和mime类型。
public class FormFile
{
public string Name { get; set; }
public string ContentType { get; set; }
public string FilePath { get; set; }
public Stream Stream { get; set; }
}
public class RequestHelper
{
public static string PostMultipart(string url, Dictionary<string, object> parameters) {
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
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;
if(parameters != null && parameters.Count > 0) {
using(Stream requestStream = request.GetRequestStream()) {
foreach(KeyValuePair<string, object> pair in parameters) {
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
if(pair.Value is FormFile) {
FormFile file = pair.Value as FormFile;
string header = "Content-Disposition: form-data; name=\"" + pair.Key + "\"; filename=\"" + file.Name + "\"\r\nContent-Type: " + file.ContentType + "\r\n\r\n";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(header);
requestStream.Write(bytes, 0, bytes.Length);
byte[] buffer = new byte[32768];
int bytesRead;
if(file.Stream == null) {
// upload from file
using(FileStream fileStream = File.OpenRead(file.FilePath)) {
while((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
fileStream.Close();
}
}
else {
// upload from given stream
while((bytesRead = file.Stream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
}
}
else {
string data = "Content-Disposition: form-data; name=\"" + pair.Key + "\"\r\n\r\n" + pair.Value;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
requestStream.Write(bytes, 0, bytes.Length);
}
}
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
requestStream.Write(trailer, 0, trailer.Length);
requestStream.Close();
}
}
using(WebResponse response = request.GetResponse()) {
using(Stream responseStream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(responseStream))
return reader.ReadToEnd();
}
}
}