使用HTTPWebrequest上传文件(multipart/form-data)

是否有任何类,库或一些代码段,可以帮助我上传文件与HTTPWebrequest?

编辑2:

我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。

编辑:

WebClient不覆盖我的要求,所以我正在寻找一个解决方案与HTTPWebrequest

454521 次浏览

我认为你正在寻找更像WebClient的东西。

具体来说,还是()

类似这样的代码很接近:(未测试的代码)

byte[] data; // data goes here.


HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = userNetworkCredentials;
request.Method = "PUT";
request.ContentType = "application/octet-stream";
request.ContentLength = data.Length;
Stream stream = request.GetRequestStream();
stream.Write(data,0,data.Length);
stream.Close();
response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
temp = reader.ReadToEnd();
reader.Close();

我一直在寻找这样的东西,在: http://bytes.com/groups/net-c/268661-how-upload-file-via-c-code(为正确而修改):

public static string UploadFilesToRemoteUrl(string url, string[] files, NameValueCollection formFields = null)
{
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");


HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Method = "POST";
request.KeepAlive = true;


Stream memStream = new System.IO.MemoryStream();


var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "--");




string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";


if (formFields != null)
{
foreach (string key in formFields.Keys)
{
string formitem = string.Format(formdataTemplate, key, formFields[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}
}


string headerTemplate =
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: application/octet-stream\r\n\r\n";


for (int i = 0; i < files.Length; i++)
{
memStream.Write(boundarybytes, 0, boundarybytes.Length);
var header = string.Format(headerTemplate, "uplTheFile", files[i]);
var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);


memStream.Write(headerbytes, 0, headerbytes.Length);


using (var fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
{
var buffer = new byte[1024];
var bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
}
}


memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
request.ContentLength = memStream.Length;


using (Stream requestStream = request.GetRequestStream())
{
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
}


using (var response = request.GetResponse())
{
Stream stream2 = response.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
return reader2.ReadToEnd();
}
}

我的ASP。NET上传常见问题解答有一篇关于此的文章,示例代码:在HttpWebRequest/WebClient中使用RFC 1867 POST请求上传文件。此代码不将文件加载到内存中(与上面的代码相反),支持多个文件,并支持表单值、设置凭据和cookie等。

编辑:看起来好像是Axosoft把这个页面删除了。谢谢你的家伙。

它仍然可以通过archive.org访问。

我最近不得不处理这个问题——另一种方法是使用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

我知道这可能有点晚了,但我一直在寻找同样的解决方案。我从一位微软代表那里找到了以下回复

private void UploadFilesToRemoteUrl(string url, string[] files, string logpath, NameValueCollection nvc)
{


long length = 0;
string boundary = "----------------------------" +
DateTime.Now.Ticks.ToString("x");




HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest2.ContentType = "multipart/form-data; boundary=" +
boundary;
httpWebRequest2.Method = "POST";
httpWebRequest2.KeepAlive = true;
httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials;






Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");




string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";


foreach(string key in nvc.Keys)
{
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}




memStream.Write(boundarybytes,0,boundarybytes.Length);


string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";


for(int i=0;i<files.Length;i++)
{


string header = string.Format(headerTemplate,"file"+i,files[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes,0,headerbytes.Length);




FileStream fileStream = new FileStream(files[i], FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];


int bytesRead = 0;


while ( (bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0 )
{
memStream.Write(buffer, 0, bytesRead);
}




memStream.Write(boundarybytes,0,boundarybytes.Length);




fileStream.Close();
}


httpWebRequest2.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest2.GetRequestStream();


memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer,0,tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer,0,tempBuffer.Length );
requestStream.Close();




WebResponse webResponse2 = httpWebRequest2.GetResponse();


Stream stream2 = webResponse2.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);


webResponse2.Close();
httpWebRequest2 = null;
webResponse2 = null;


}

我永远不能让例子正常工作,我总是收到一个500错误时,把它发送到服务器。

然而,我在这个url中遇到了一个非常优雅的方法

它很容易扩展,显然可以处理二进制文件和XML。

你可以用类似的方法来称呼它

class Program
{
public static string gsaFeedURL = "http://yourGSA.domain.com:19900/xmlfeed";


static void Main()
{
try
{
postWebData();
}
catch (Exception ex)
{
}
}


// new one I made from C# web service
public static void postWebData()
{
StringDictionary dictionary = new StringDictionary();
UploadSpec uploadSpecs = new UploadSpec();
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes;
Uri gsaURI = new Uri(gsaFeedURL);  // Create new URI to GSA feeder gate
string sourceURL = @"C:\FeedFile.xml"; // Location of the XML feed file
// Two parameters to send
string feedtype = "full";
string datasource = "test";


try
{
// Add the parameter values to the dictionary
dictionary.Add("feedtype", feedtype);
dictionary.Add("datasource", datasource);


// Load the feed file created and get its bytes
XmlDocument xml = new XmlDocument();
xml.Load(sourceURL);
bytes = Encoding.UTF8.GetBytes(xml.OuterXml);


// Add data to upload specs
uploadSpecs.Contents = bytes;
uploadSpecs.FileName = sourceURL;
uploadSpecs.FieldName = "data";


// Post the data
if ((int)HttpUpload.Upload(gsaURI, dictionary, uploadSpecs).StatusCode == 200)
{
Console.WriteLine("Successful.");
}
else
{
// GSA POST not successful
Console.WriteLine("Failure.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

采用上面的代码并修复,因为它抛出内部服务器错误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);

可以扩展它来处理多个文件,或者对每个文件多次调用它。但它适合你的需要。

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

采取以上和修改它接受一些头值,和多个文件

    NameValueCollection headers = new NameValueCollection();
headers.Add("Cookie", "name=value;");
headers.Add("Referer", "http://google.com");
NameValueCollection nvc = new NameValueCollection();
nvc.Add("name", "value");


HttpUploadFile(url, new string[] { "c:\\file1.txt", "c:\\file2.jpg" }, new string[] { "file", "image" }, new string[] { "application/octet-stream", "image/jpeg" }, nvc, headers);

public static void HttpUploadFile(string url, string[] file, string[] paramName, string[] contentType, NameValueCollection nvc, NameValueCollection headerItems)
{
//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);


foreach (string key in headerItems.Keys)
{
if (key == "Referer")
{
wr.Referer = headerItems[key];
}
else
{
wr.Headers.Add(key, headerItems[key]);
}
}


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 = "";


for(int i =0; i<file.Count();i++)
{
header = string.Format(headerTemplate, paramName[i], System.IO.Path.GetFileName(file[i]), contentType[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);


FileStream fileStream = new FileStream(file[i], 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();
rs.Write(boundarybytes, 0, boundarybytes.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);
wresp.Close();
wresp = null;
}
finally
{
wr = null;
}
}

这里有另一个我的评论的工作示例:

        List<MimePart> mimeParts = new List<MimePart>();


try
{
foreach (string key in form.AllKeys)
{
StringMimePart part = new StringMimePart();


part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
part.StringData = form[key];


mimeParts.Add(part);
}


int nameIndex = 0;


foreach (UploadFile file in files)
{
StreamMimePart part = new StreamMimePart();


if (string.IsNullOrEmpty(file.FieldName))
file.FieldName = "file" + nameIndex++;


part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
part.Headers["Content-Type"] = file.ContentType;


part.SetStream(file.Data);


mimeParts.Add(part);
}


string boundary = "----------" + DateTime.Now.Ticks.ToString("x");


req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";


long contentLength = 0;


byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");


foreach (MimePart part in mimeParts)
{
contentLength += part.GenerateHeaderFooterData(boundary);
}


req.ContentLength = contentLength + _footer.Length;


byte[] buffer = new byte[8192];
byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
int read;


using (Stream s = req.GetRequestStream())
{
foreach (MimePart part in mimeParts)
{
s.Write(part.Header, 0, part.Header.Length);


while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
s.Write(buffer, 0, read);


part.Data.Dispose();


s.Write(afterFile, 0, afterFile.Length);
}


s.Write(_footer, 0, _footer.Length);
}


return (HttpWebResponse)req.GetResponse();
}
catch
{
foreach (MimePart part in mimeParts)
if (part.Data != null)
part.Data.Dispose();


throw;
}

这里有一个使用的例子:

            UploadFile[] files = new UploadFile[]
{
new UploadFile(@"C:\2.jpg","new_file","image/jpeg") //new_file is id of upload field
};


NameValueCollection form = new NameValueCollection();


form["id_hidden_input"] = "value_hidden_inpu"; //there is additional param (hidden fields on page)




HttpWebRequest req = (HttpWebRequest)WebRequest.Create(full URL of action);


// set credentials/cookies etc.
req.CookieContainer = hrm.CookieContainer; //hrm is my class. i copied all cookies from last request to current (for auth)
HttpWebResponse resp = HttpUploadHelper.Upload(req, files, form);


using (Stream s = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(s))
{
string response = sr.ReadToEnd();
}
//profit!

查看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

对于我来说,下面的作品(主要是受到以下所有回答的启发),我从Elad的回答开始,修改/简化事情以符合我的需要(删除不是文件形式输入,只有一个文件,……)

希望它能帮助到一些人:)

(PS:我知道异常处理没有实现,并且假设它是在一个类中编写的,所以我可能需要一些集成工作…)

private void uploadFile()
{
Random rand = new Random();
string boundary = "----boundary" + rand.Next().ToString();
Stream data_stream;
byte[] header = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"file_path\"; filename=\"" + System.IO.Path.GetFileName(this.file) + "\"\r\nContent-Type: application/octet-stream\r\n\r\n");
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");


// Do the request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MBF_URL);
request.UserAgent = "My Toolbox";
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "multipart/form-data; boundary=" + boundary;
data_stream = request.GetRequestStream();
data_stream.Write(header, 0, header.Length);
byte[] file_bytes = System.IO.File.ReadAllBytes(this.file);
data_stream.Write(file_bytes, 0, file_bytes.Length);
data_stream.Write(trailer, 0, trailer.Length);
data_stream.Close();


// Read the response
WebResponse response = request.GetResponse();
data_stream = response.GetResponseStream();
StreamReader reader = new StreamReader(data_stream);
this.url = reader.ReadToEnd();


if (this.url == "") { this.url = "No response :("; }


reader.Close();
data_stream.Close();
response.Close();
}

基于上面提供的代码,我添加了对多个文件的支持,也可以直接上传流,而不需要有本地文件。

要将文件上传到包含一些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();
}




}
}

更新:使用。net 4.5(或从NuGet中添加Microsoft.Net.Http包的。net 4.0),这是可能的,不需要外部代码,扩展和“低级”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();
}
}

不确定这是否张贴之前,但我得到了这个工作与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中做文件上传和添加一些参数到多部分/表单数据请求。NET而不是通过正规的表单发布。 感谢@JoshCodes的回答,我找到了我一直在寻找的方向。 我发布我的解决方案是为了帮助其他人找到一种方法来使用文件和参数来执行帖子 html等价于我试图实现的是: html < / p >
<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>
由于我必须提供apiKey和签名(这是请求参数和api密钥连接字符串的计算校验和),我需要在服务器端完成它。 我需要在服务器端执行它的另一个原因是,文件的发布可以在任何时候通过指向服务器上已经存在的文件(提供路径)来执行,因此在表单发布期间不会手动选择文件,因此表单数据文件将不包含文件流。否则,我可以通过ajax回调计算校验和,并使用JQuery通过html post提交文件。 我使用的是。net 4.0版本,在实际解决方案中无法升级到4.5。所以我必须安装Microsoft.Net.Http使用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

修改了@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();
}
}

我写了一个类使用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框架。

客户端使用转换文件ToBase64String,使用Xml发布后 到服务器调用,此服务器使用File.WriteAllBytes(path,Convert.FromBase64String(dataFile_Client_sent)).

.

好幸运!

该方法适用于同时上传多张图片

        var flagResult = new viewModel();
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 = method;
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;


Stream rs = wr.GetRequestStream();




string path = @filePath;
System.IO.DirectoryInfo folderInfo = new DirectoryInfo(path);


foreach (FileInfo file in folderInfo.GetFiles())
{
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.FullName, 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);
var result = reader2.ReadToEnd();
var cList = JsonConvert.DeserializeObject<HttpViewModel>(result);
if (cList.message=="images uploaded!")
{
flagResult.success = true;
}


}
catch (Exception ex)
{
//log.Error("Error uploading file", ex);
if (wresp != null)
{
wresp.Close();
wresp = null;
}
}
finally
{
wr = null;
}
return flagResult;
}