Carregar arquivos com HTTPWebrequest (multipart / form-data)

Existe alguma class, biblioteca ou algum pedaço de código que me ajudará a fazer upload de arquivos com o HTTPWebrequest ?

Editar 2:

Eu não quero fazer upload para uma pasta WebDAV ou algo parecido. Eu quero simular um navegador, assim como você carrega seu avatar em um fórum ou envia um arquivo via formulário em um aplicativo da web. Carregar para um formulário que usa dados de várias partes / formulários.

Editar:

O WebClient não cobre meus requisitos, então estou procurando uma solução com o HTTPWebrequest .

Levou o código acima e corrigiu porque ele gera Internal Server Error 500. Existem alguns problemas com \ r \ n mal posicionados e espaços, etc. Aplicado a refatoração com stream de memory, escrevendo diretamente para o stream de requisição. Aqui está o resultado:

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; } } 

e uso de amostra:

  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); 

Ele pode ser estendido para manipular vários arquivos ou simplesmente chamá-lo várias vezes para cada arquivo. No entanto, atende às suas necessidades.

Eu estava procurando por algo assim, encontrado em: http://bytes.com/groups/net-c/268661-how-upload-file-via-c-code (modificado para correção):

 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(); } } 

ATUALIZAÇÃO: Usando o .NET 4.5 (ou .NET 4.0 adicionando o pacote Microsoft.Net.Http do NuGet) isso é possível sem código externo, extensões e manipulação HTTP de “baixo nível”. Aqui está um exemplo:

 // Perform the equivalent of posting a form with a filename and two files, in HTML: // 
// // // //
private async Task 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 // formData.Add(stringContent, "filename", "filename"); // formData.Add(fileStreamContent, "file1", "file1"); // 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(); } }

Minha FAQ de Upload do ASP.NET tem um artigo sobre isso, com código de exemplo: Envie arquivos usando uma solicitação POST RFC 1867 com HttpWebRequest / WebClient . Este código não carrega arquivos na memory (em oposição ao código acima), suporta múltiplos arquivos e suporta valores de formulário, configuração de credenciais e cookies, etc.

Edit: parece que Axosoft derrubou a página. Obrigado rapazes.

Ainda é acessível via archive.org.

Com base no código fornecido acima, adicionei suporte a vários arquivos e também ao upload de um stream diretamente, sem a necessidade de ter um arquivo local.

Para fazer upload de arquivos para um URL específico, incluindo alguns pós-programas, faça o seguinte:

 RequestHelper.PostMultipart( "http://sofpt.miximages.com/.net/upload.php, new Dictionarystring, 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 } }, }); 

Para melhorar ainda mais, pode-se determinar o nome e o tipo MIME do próprio arquivo.

 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 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 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(); } } } 

algo assim está próximo: (código não testado)

 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(); 

Levou o acima e modificou-o aceitar alguns valores de header e vários arquivos

  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 

Eu acho que você está procurando por algo mais como o WebClient .

Especificamente, UploadFile () .

Exemplo VB (convertido do exemplo C # em outro post):

 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 

Eu tive que lidar com isso recentemente – outra maneira de abordá-lo é usar o fato de que o WebClient é herdável e alterar o WebRequest subjacente de lá:

http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest(VS.80).aspx

Eu prefiro o C #, mas se você está preso com o VB os resultados serão algo como isto:

 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 

Há outro exemplo de trabalho com alguns dos meus comentários:

  List mimeParts = new List(); 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; } 

E há um exemplo de uso:

  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! 

Eu estava olhando para fazer upload de arquivos e adicionar alguns parâmetros para uma solicitação de dados de formulário / multipart em VB.NET e não através de um post de formulários regulares. Graças à resposta do @JoshCodes, obtive a direção que estava procurando. Estou postando minha solução para ajudar outras pessoas a encontrar uma maneira de executar uma postagem com arquivos e parâmetros. O equivalente HTML do que tento obter é: html

 

Devido ao fato de que eu tenho que fornecer o apiKey e a assinatura (que é uma sum de verificação calculada dos parâmetros de solicitação e da string API concatenada), eu precisava fazer isso do lado do servidor. A outra razão que eu precisava para fazer isso do lado do servidor é o fato de que o post do arquivo pode ser executado a qualquer momento, apontando para um arquivo já no servidor (fornecendo o caminho), então não haveria nenhum arquivo selecionado manualmente durante o formulário postar assim arquivo de dados de formulário não conteria o stream de arquivo.Caso contrário, eu poderia ter calculado a sum de verificação através de um retorno de chamada ajax e submetido o arquivo através do post html usando JQuery. Eu estou usando .net versão 4.0 e não é possível atualizar para 4.5 na solução real. Então eu tive que instalar o Microsoft.Net.Http usando 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 

Não tenho certeza se isso foi postado antes, mas eu comecei a trabalhar com o WebClient. Eu li a documentação para o WebClient. Um ponto chave que eles fazem é

Se a propriedade BaseAddress não for uma cadeia vazia (“”) e o endereço não contiver um URI absoluto, o endereço deverá ser um URI relativo combinado com o BaseAddress para formar o URI absoluto dos dados solicitados. Se a propriedade QueryString não for uma string vazia, ela será anexada ao endereço.

Então, tudo que fiz foi wc.QueryString.Add (“source”, generatedImage) para adicionar os diferentes parâmetros de consulta e de alguma forma ele corresponde ao nome da propriedade com a imagem que eu enviei. Espero que ajude

  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(); } 

Modifique o código @CristianRomanescu para trabalhar com stream de memory, aceite o arquivo como uma matriz de bytes, permita nvc nulo, retorne a resposta da solicitação e trabalhe com o header Authorization. Testado o código com o 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; } } 

Código de teste:

 [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(); } } 

Eu escrevi uma class usando o WebClient quando fiz o upload de formulários com várias partes.

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); } } } 

This will work with all versions of the .NET framework.

I can never get the examples to work properly, I always receive a 500 error when sending it to the server.

However I came across a very elegant method of doing it in this url

It is easily extendible and obviously works with binary files as well as XML.

You call it using something similar to this

 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); } } } 

For me, the following works (mostly inspirated from all of the following answers), I started from Elad’s answer and modify/simplify things to match my need (remove not file form inputs, only one file, …).

Hope it can helps somebody 🙂

(PS: I know that exception handling is not implemented and it assumes that it was written inside a class, so I may need some integration effort…)

 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(); } 

Check out the MyToolkit library:

 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

Client use convert File to ToBase64String , after use Xml to promulgate to Server call, this server use File.WriteAllBytes(path,Convert.FromBase64String(dataFile_Client_sent)) .

Good lucky!

I realize this is probably really late, but I was searching for the same solution. I found the following response from a Microsoft rep

 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