是否有任何类,库或一些代码片段,将帮助我上传文件与HTTPWebrequest?
编辑2:
我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。
编辑:
WebClient不覆盖我的需求,所以我正在寻找一个解决方案与HTTPWebrequest。
是否有任何类,库或一些代码片段,将帮助我上传文件与HTTPWebrequest?
编辑2:
我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。
编辑:
WebClient不覆盖我的需求,所以我正在寻找一个解决方案与HTTPWebrequest。
当前回答
我想在VB中做文件上传和添加一些参数到multipart/form-data请求。NET而不是通过正规的表单发布。 感谢@JoshCodes的回答,我找到了我一直在寻找的方向。 我发布我的解决方案是为了帮助其他人找到一种方法来使用文件和参数来执行帖子 html等价于我试图实现的是: 超文本标记语言
<form action="your-api-endpoint" enctype="multipart/form-data" method="post">
<input type="hidden" name="action" value="api-method-name"/>
<input type="hidden" name="apiKey" value="gs1xxxxxxxxxxxxxex"/>
<input type="hidden" name="access" value="protected"/>
<input type="hidden" name="name" value="test"/>
<input type="hidden" name="title" value="test"/>
<input type="hidden" name="signature" value="cf1d4xxxxxxxxcd5"/>
<input type="file" name="file"/>
<input type="submit" name="_upload" value="Upload"/>
</form>
Due to the fact that I have to provide the apiKey and the signature (which is a calculated checksum of the request parameters and api key concatenated string), I needed to do it server side. The other reason I needed to do it server side is the fact that the post of the file can be performed at any time by pointing to a file already on the server (providing the path), so there would be no manually selected file during form post thus form data file would not contain the file stream.Otherwise I could have calculated the checksum via an ajax callback and submitted the file through the html post using JQuery. I am using .net version 4.0 and cannot upgrade to 4.5 in the actual solution. So I had to install the Microsoft.Net.Http using nuget cmd
PM> install-package Microsoft.Net.Http
Private Function UploadFile(req As ApiRequest, filePath As String, fileName As String) As String
Dim result = String.empty
Try
''//Get file stream
Dim paramFileStream As Stream = File.OpenRead(filePath)
Dim fileStreamContent As HttpContent = New StreamContent(paramFileStream)
Using client = New HttpClient()
Using formData = New MultipartFormDataContent()
''// This adds parameter name ("action")
''// parameter value (req.Action) to form data
formData.Add(New StringContent(req.Action), "action")
formData.Add(New StringContent(req.ApiKey), "apiKey")
For Each param In req.Parameters
formData.Add(New StringContent(param.Value), param.Key)
Next
formData.Add(New StringContent(req.getRequestSignature.Qualifier), "signature")
''//This adds the file stream and file info to form data
formData.Add(fileStreamContent, "file", fileName)
''//We are now sending the request
Dim response = client.PostAsync(GetAPIEndpoint(), formData).Result
''//We are here reading the response
Dim readR = New StreamReader(response.Content.ReadAsStreamAsync().Result, Encoding.UTF8)
Dim respContent = readR.ReadToEnd()
If Not response.IsSuccessStatusCode Then
result = "Request Failed : Code = " & response.StatusCode & "Reason = " & response.ReasonPhrase & "Message = " & respContent
End If
result.Value = respContent
End Using
End Using
Catch ex As Exception
result = "An error occurred : " & ex.Message
End Try
Return result
End Function
其他回答
不确定这是否张贴之前,但我得到了这个工作与WebClient。我读了WebClient的文档。他们提出的一个关键点是
如果BaseAddress属性不是空字符串("")和address 不包含绝对URI,地址必须是相对URI那 与BaseAddress结合形成所请求的URI的绝对URI 数据。如果QueryString属性不是空字符串,那么它就是空字符串 附于地址。
我所做的就是wc。querystring。添加(“源”,generatedImage)来添加不同的查询参数,以某种方式将属性名称与我上传的图像匹配。希望能有所帮助
public void postImageToFacebook(string generatedImage, string fbGraphUrl)
{
WebClient wc = new WebClient();
byte[] bytes = System.IO.File.ReadAllBytes(generatedImage);
wc.QueryString.Add("source", generatedImage);
wc.QueryString.Add("message", "helloworld");
wc.UploadFile(fbGraphUrl, generatedImage);
wc.Dispose();
}
VB示例(从另一篇文章中的c#示例转换而来):
Private Sub HttpUploadFile( _
ByVal uri As String, _
ByVal filePath As String, _
ByVal fileParameterName As String, _
ByVal contentType As String, _
ByVal otherParameters As Specialized.NameValueCollection)
Dim boundary As String = "---------------------------" & DateTime.Now.Ticks.ToString("x")
Dim newLine As String = System.Environment.NewLine
Dim boundaryBytes As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" & boundary & newLine)
Dim request As Net.HttpWebRequest = Net.WebRequest.Create(uri)
request.ContentType = "multipart/form-data; boundary=" & boundary
request.Method = "POST"
request.KeepAlive = True
request.Credentials = Net.CredentialCache.DefaultCredentials
Using requestStream As IO.Stream = request.GetRequestStream()
Dim formDataTemplate As String = "Content-Disposition: form-data; name=""{0}""{1}{1}{2}"
For Each key As String In otherParameters.Keys
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
Dim formItem As String = String.Format(formDataTemplate, key, newLine, otherParameters(key))
Dim formItemBytes As Byte() = Text.Encoding.UTF8.GetBytes(formItem)
requestStream.Write(formItemBytes, 0, formItemBytes.Length)
Next key
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"
Dim header As String = String.Format(headerTemplate, fileParameterName, filePath, newLine, contentType)
Dim headerBytes As Byte() = Text.Encoding.UTF8.GetBytes(header)
requestStream.Write(headerBytes, 0, headerBytes.Length)
Using fileStream As New IO.FileStream(filePath, IO.FileMode.Open, IO.FileAccess.Read)
Dim buffer(4096) As Byte
Dim bytesRead As Int32 = fileStream.Read(buffer, 0, buffer.Length)
Do While (bytesRead > 0)
requestStream.Write(buffer, 0, bytesRead)
bytesRead = fileStream.Read(buffer, 0, buffer.Length)
Loop
End Using
Dim trailer As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" + boundary + "--" & newLine)
requestStream.Write(trailer, 0, trailer.Length)
End Using
Dim response As Net.WebResponse = Nothing
Try
response = request.GetResponse()
Using responseStream As IO.Stream = response.GetResponseStream()
Using responseReader As New IO.StreamReader(responseStream)
Dim responseText = responseReader.ReadToEnd()
Diagnostics.Debug.Write(responseText)
End Using
End Using
Catch exception As Net.WebException
response = exception.Response
If (response IsNot Nothing) Then
Using reader As New IO.StreamReader(response.GetResponseStream())
Dim responseText = reader.ReadToEnd()
Diagnostics.Debug.Write(responseText)
End Using
response.Close()
End If
Finally
request = Nothing
End Try
End Sub
采用上面的代码并修复,因为它抛出内部服务器错误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);
可以扩展它来处理多个文件,或者对每个文件多次调用它。但它适合你的需要。
我写了一个类使用WebClient方式做多部分的表单上传。
http://ferozedaud.blogspot.com/2010/03/multipart-form-upload-helper.html
///
/// MimePart
/// Abstract class for all MimeParts
///
abstract class MimePart
{
public string Name { get; set; }
public abstract string ContentDisposition { get; }
public abstract string ContentType { get; }
public abstract void CopyTo(Stream stream);
public String Boundary
{
get;
set;
}
}
class NameValuePart : MimePart
{
private NameValueCollection nameValues;
public NameValuePart(NameValueCollection nameValues)
{
this.nameValues = nameValues;
}
public override void CopyTo(Stream stream)
{
string boundary = this.Boundary;
StringBuilder sb = new StringBuilder();
foreach (object element in this.nameValues.Keys)
{
sb.AppendFormat("--{0}", boundary);
sb.Append("\r\n");
sb.AppendFormat("Content-Disposition: form-data; name=\"{0}\";", element);
sb.Append("\r\n");
sb.Append("\r\n");
sb.Append(this.nameValues[element.ToString()]);
sb.Append("\r\n");
}
sb.AppendFormat("--{0}", boundary);
sb.Append("\r\n");
//Trace.WriteLine(sb.ToString());
byte [] data = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(data, 0, data.Length);
}
public override string ContentDisposition
{
get { return "form-data"; }
}
public override string ContentType
{
get { return String.Empty; }
}
}
class FilePart : MimePart
{
private Stream input;
private String contentType;
public FilePart(Stream input, String name, String contentType)
{
this.input = input;
this.contentType = contentType;
this.Name = name;
}
public override void CopyTo(Stream stream)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Content-Disposition: {0}", this.ContentDisposition);
if (this.Name != null)
sb.Append("; ").AppendFormat("name=\"{0}\"", this.Name);
if (this.FileName != null)
sb.Append("; ").AppendFormat("filename=\"{0}\"", this.FileName);
sb.Append("\r\n");
sb.AppendFormat(this.ContentType);
sb.Append("\r\n");
sb.Append("\r\n");
// serialize the header data.
byte[] buffer = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(buffer, 0, buffer.Length);
// send the stream.
byte[] readBuffer = new byte[1024];
int read = input.Read(readBuffer, 0, readBuffer.Length);
while (read > 0)
{
stream.Write(readBuffer, 0, read);
read = input.Read(readBuffer, 0, readBuffer.Length);
}
// write the terminating boundary
sb.Length = 0;
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary);
sb.Append("\r\n");
buffer = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(buffer, 0, buffer.Length);
}
public override string ContentDisposition
{
get { return "file"; }
}
public override string ContentType
{
get {
return String.Format("content-type: {0}", this.contentType);
}
}
public String FileName { get; set; }
}
///
/// Helper class that encapsulates all file uploads
/// in a mime part.
///
class FilesCollection : MimePart
{
private List files;
public FilesCollection()
{
this.files = new List();
this.Boundary = MultipartHelper.GetBoundary();
}
public int Count
{
get { return this.files.Count; }
}
public override string ContentDisposition
{
get
{
return String.Format("form-data; name=\"{0}\"", this.Name);
}
}
public override string ContentType
{
get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
}
public override void CopyTo(Stream stream)
{
// serialize the headers
StringBuilder sb = new StringBuilder(128);
sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(headerBytes, 0, headerBytes.Length);
foreach (FilePart part in files)
{
part.Boundary = this.Boundary;
part.CopyTo(stream);
}
}
public void Add(FilePart part)
{
this.files.Add(part);
}
}
///
/// Helper class to aid in uploading multipart
/// entities to HTTP web endpoints.
///
class MultipartHelper
{
private static Random random = new Random(Environment.TickCount);
private List formData = new List();
private FilesCollection files = null;
private MemoryStream bufferStream = new MemoryStream();
private string boundary;
public String Boundary { get { return boundary; } }
public static String GetBoundary()
{
return Environment.TickCount.ToString("X");
}
public MultipartHelper()
{
this.boundary = MultipartHelper.GetBoundary();
}
public void Add(NameValuePart part)
{
this.formData.Add(part);
part.Boundary = boundary;
}
public void Add(FilePart part)
{
if (files == null)
{
files = new FilesCollection();
}
this.files.Add(part);
}
public void Upload(WebClient client, string address, string method)
{
// set header
client.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + this.boundary);
Trace.WriteLine("Content-Type: multipart/form-data; boundary=" + this.boundary + "\r\n");
// first, serialize the form data
foreach (NameValuePart part in this.formData)
{
part.CopyTo(bufferStream);
}
// serialize the files.
this.files.CopyTo(bufferStream);
if (this.files.Count > 0)
{
// add the terminating boundary.
StringBuilder sb = new StringBuilder();
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte [] buffer = Encoding.ASCII.GetBytes(sb.ToString());
bufferStream.Write(buffer, 0, buffer.Length);
}
bufferStream.Seek(0, SeekOrigin.Begin);
Trace.WriteLine(Encoding.ASCII.GetString(bufferStream.ToArray()));
byte [] response = client.UploadData(address, method, bufferStream.ToArray());
Trace.WriteLine("----- RESPONSE ------");
Trace.WriteLine(Encoding.ASCII.GetString(response));
}
///
/// Helper class that encapsulates all file uploads
/// in a mime part.
///
class FilesCollection : MimePart
{
private List files;
public FilesCollection()
{
this.files = new List();
this.Boundary = MultipartHelper.GetBoundary();
}
public int Count
{
get { return this.files.Count; }
}
public override string ContentDisposition
{
get
{
return String.Format("form-data; name=\"{0}\"", this.Name);
}
}
public override string ContentType
{
get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
}
public override void CopyTo(Stream stream)
{
// serialize the headers
StringBuilder sb = new StringBuilder(128);
sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(headerBytes, 0, headerBytes.Length);
foreach (FilePart part in files)
{
part.Boundary = this.Boundary;
part.CopyTo(stream);
}
}
public void Add(FilePart part)
{
this.files.Add(part);
}
}
}
class Program
{
static void Main(string[] args)
{
Trace.Listeners.Add(new ConsoleTraceListener());
try
{
using (StreamWriter sw = new StreamWriter("testfile.txt", false))
{
sw.Write("Hello there!");
}
using (Stream iniStream = File.OpenRead(@"c:\platform.ini"))
using (Stream fileStream = File.OpenRead("testfile.txt"))
using (WebClient client = new WebClient())
{
MultipartHelper helper = new MultipartHelper();
NameValueCollection props = new NameValueCollection();
props.Add("fname", "john");
props.Add("id", "acme");
helper.Add(new NameValuePart(props));
FilePart filepart = new FilePart(fileStream, "pics1", "text/plain");
filepart.FileName = "1.jpg";
helper.Add(filepart);
FilePart ini = new FilePart(iniStream, "pics2", "text/plain");
ini.FileName = "inifile.ini";
helper.Add(ini);
helper.Upload(client, "http://localhost/form.aspx", "POST");
}
}
catch (Exception e)
{
Trace.WriteLine(e);
}
}
}
这将适用于所有版本的. net框架。
修改了@CristianRomanescu代码,以使用内存流,接受文件作为字节数组,允许空nvc,返回请求响应和使用授权头。使用Web Api 2测试代码。
private string HttpUploadFile(string url, byte[] file, string fileName, string paramName, string contentType, NameValueCollection nvc, string authorizationHeader)
{
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.Headers.Add("Authorization", authorizationHeader);
wr.KeepAlive = true;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
if (nvc != null)
{
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, fileName, contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
rs.Write(file, 0, file.Length);
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);
var response = reader2.ReadToEnd();
return response;
}
catch (Exception ex)
{
if (wresp != null)
{
wresp.Close();
wresp = null;
}
return null;
}
finally
{
wr = null;
}
}
Testcode:
[HttpPost]
[Route("postformdata")]
public IHttpActionResult PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = new MultipartMemoryStreamProvider();
try
{
// Read the form data.
var result = Request.Content.ReadAsMultipartAsync(provider).Result;
string response = "";
// This illustrates how to get the file names.
foreach (var file in provider.Contents)
{
var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = file.ReadAsByteArrayAsync().Result;
response = HttpUploadFile("https://localhost/api/v1/createfromfile", buffer, fileName, "file", "application/pdf", null, "AuthorizationKey");
}
return Ok(response);
}
catch (System.Exception e)
{
return InternalServerError();
}
}