.net - formdata - send file httpwebrequest c#
Cargar archivos con HTTPWebrequest(multipart/form-data) (20)
ACTUALIZACIÓN: utilizando .NET 4.5 (o .NET 4.0 agregando el paquete Microsoft.Net.Http de NuGet), esto es posible sin código externo, extensiones y manipulación HTTP de "bajo nivel". Aquí hay un ejemplo:
// 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();
}
}
¿Hay alguna clase, biblioteca o código que me ayude a subir archivos con HTTPWebrequest ?
Edición 2:
No quiero subir a una carpeta WebDAV o algo así. Quiero simular un navegador, así como subir tu avatar a un foro o cargar un archivo a través de un formulario en una aplicación web. Subir a un formulario que utiliza un multipart / form-data.
Editar:
WebClient no cubre mis requisitos, por lo que estoy buscando una solución con HTTPWebrequest .
Basándome en el código provisto anteriormente, agregué soporte para múltiples archivos y también subí un flujo directamente sin la necesidad de tener un archivo local.
Para cargar archivos en una URL específica, incluidos algunos parámetros de publicación, haga lo siguiente:
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 } },
});
Para mejorar esto aún más, uno podría determinar el nombre y el tipo mime del archivo dado.
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();
}
}
}
Creo que estás buscando algo más como WebClient .
Específicamente, UploadFile() .
Ejemplo de VB (convertido de ejemplo de C # en otra publicación):
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
Escribí una clase usando WebClient desde cuándo realizar la carga multipartita.
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);
}
}
}
Esto funcionará con todas las versiones de .NET framework.
Estaba buscando algo como esto, Encontrado en: http://bytes.com/groups/net-c/268661-how-upload-file-via-c-code (modificado para la corrección):
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();
}
}
Estaba buscando subir archivos y agregar algunos parámetros a una solicitud multipart / form-data en VB.NET y no a través de una publicación de formularios regulares. Gracias a la respuesta de @JoshCodes, obtuve la dirección que estaba buscando. Estoy publicando mi solución para ayudar a otros a encontrar una manera de realizar una publicación con el archivo y los parámetros. El equivalente html de lo que trato de lograr es: 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>
Debido al hecho de que tengo que proporcionar el apiKey y la firma (que es una suma de comprobación calculada de los parámetros de solicitud y la cadena concatenada de clave api), tuve que hacerlo del lado del servidor. La otra razón por la que necesitaba hacerlo desde el lado del servidor es el hecho de que la publicación del archivo se puede realizar en cualquier momento señalando un archivo que ya se encuentra en el servidor (proporcionando la ruta), por lo que no habría ningún archivo seleccionado manualmente durante el formulario el archivo de datos del formulario, por lo tanto, no contendría el flujo de archivos. De lo contrario, podría haber calculado la suma de comprobación mediante una devolución de llamada ajax y haber enviado el archivo a través del mensaje html utilizando JQuery. Estoy utilizando .net versión 4.0 y no puedo actualizar a 4.5 en la solución real. Así que tuve que instalar 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
Hay otro ejemplo de trabajo con algunos de mis comentarios:
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;
}
Y hay ejemplo de usar:
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!
Mi FAQ de carga de ASP.NET tiene un artículo sobre esto, con un código de ejemplo: Cargar archivos usando una solicitud POST RFC 1867 con HttpWebRequest / WebClient . Este código no carga archivos en la memoria (a diferencia del código anterior), admite múltiples archivos y admite valores de formulario, configuración de credenciales y cookies, etc.
Edición: parece que Axosoft bajó la página. Gracias chicos.
Todavía es accesible a través de archive.org.
No estoy seguro de si esto se publicó antes pero conseguí esto trabajando con WebClient. Leí la documentación para el cliente web. Un punto clave que hacen es
Si la propiedad BaseAddress no es una cadena vacía ("") y la dirección no contiene un URI absoluto, la dirección debe ser un URI relativo que se combine con BaseAddress para formar el URI absoluto de los datos solicitados. Si la propiedad QueryString no es una cadena vacía, se adjunta a la dirección.
Así que todo lo que hice fue wc.QueryString.Add ("source", genericImage) para agregar los diferentes parámetros de consulta y de alguna manera coincide con el nombre de la propiedad con la imagen que cargué. Espero eso ayude
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();
}
Se modificó el código de @CristianRomanescu para trabajar con el flujo de memoria, aceptar el archivo como una matriz de bytes, permitir nvc nulo, respuesta de solicitud de retorno y trabajar con el encabezado de autorización. Probado el código con 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 prueba:
[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();
}
}
Tomó el código anterior y lo arregló porque arroja el Error interno del servidor 500. Hay algunos problemas con / r / n mal posicionados y espacios, etc. Se aplicó la refactorización con el flujo de memoria, escribiendo directamente en el flujo de solicitud. Aquí está el 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;
}
}
y uso de la muestra:
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);
Podría extenderse para manejar múltiples archivos o simplemente llamarlo varias veces para cada archivo. Sin embargo, se adapta a sus necesidades.
Tomó lo anterior y lo modificó, acepta algunos valores de encabezado y varios archivos.
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;
}
}
Tuve que lidiar con esto recientemente. Otra forma de abordarlo es utilizar el hecho de que WebClient es heredable y cambiar la WebRequest subyacente desde allí:
http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest(VS.80).aspx
Prefiero C #, pero si te quedas con VB, los resultados se verán así:
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
algo como esto está cerca: (código no probado)
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();
Echa un vistazo a la biblioteca 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);
Nunca puedo conseguir que los ejemplos funcionen correctamente, siempre recibo un error 500 cuando lo envío al servidor.
Sin embargo, me encontré con un método muy elegante de hacerlo en esta url
Es fácilmente extensible y, obviamente, funciona con archivos binarios y XML.
Lo llamas usando algo similar a esto.
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);
}
}
}
Para mí, los siguientes trabajos (inspirados principalmente en todas las respuestas siguientes), comencé a partir de la respuesta de Elad y modifiqué / simplifiqué las cosas para que coincidieran con mi necesidad (eliminar no las entradas del formulario, solo un archivo, ...)
Espero que pueda ayudar a alguien :)
(PD: Sé que el manejo de excepciones no está implementado y se supone que fue escrito dentro de una clase, por lo que es posible que necesite un poco de esfuerzo de integración ...)
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();
}
El uso del cliente convierte el archivo a ToBase64String
, después de usar Xml para promulgar la llamada al servidor, este servidor lo utiliza File.WriteAllBytes(path,Convert.FromBase64String(dataFile_Client_sent))
.
¡Buena suerte!
Me doy cuenta de que esto probablemente sea muy tarde, pero estaba buscando la misma solución. He encontrado la siguiente respuesta de un representante de Microsoft
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;
}