2012-01-04 14 views
11

Necesito hacer un HTTP POST usando C#. Necesita hacer una devolución de datos de la misma manera que una página IE6.Publicación de HTTP como IE6 usando C#

De la documentación de la devolución de datos debe ser similar

POST /.../Upload.asp?b_customerId=[O/M1234] HTTP/1.1 
Content-length: 12345 
Content-type: multipart/form-data; boundary=vxvxv 
Host: www.foo.com 
--vxvxv 
Content-disposition: form-data; name=”File1”; filename=”noColonsSpacesOrAmpersandsInHere” 
Content-type: text/xml 
<?xml version=”1.0” encoding=”UTF-8”?> 
... 
<bat:Batch ... 
....... 
</bat:Batch> 
--vxvxv-- 

Creo que estoy teniendo problemas con los caracteres de contorno. Traté de establecer el límite en los datos de la publicación y violín muestra algo similar, pero me devuelve una página con el error "Llamada o argumento de procedimiento no válido". la disposición de contenido está en el cuerpo en lugar del encabezado para mantenerlo dentro de los límites. No estoy seguro de que sea correcto. ¿Estoy estableciendo el límite de la manera correcta? ¿Alguien puede dar alguna orientación sobre cómo hacer un HTTP POST de estilo IE6 usando C#? Gracias

Mi Código

data = "--vxvxv" + Environment.NewLine + 
    "Content-disposition: form-data; name=\"File1\";" + Environment.NewLine + 
    "filename=\"provideTest.xml\"" + Environment.NewLine + 
    "Content-type: text/xml" + Environment.NewLine + 
    @"<?xml version=""1.0"" encoding=""UTF-8""?>" + Environment.NewLine + 
    data + Environment.NewLine + 
    "--vxvxv--"; 

var encoding = ASCIIEncoding.UTF8; 
HttpWebRequest request; 
var postData = encoding.GetBytes(data); 

request = (HttpWebRequest)WebRequest.Create(url); 
request.ContentLength = postData.Length; 
request.Method = "POST"; 
request.ContentType = "multipart/form-data; boundary=vxvxv"; 
request.Host = "www.foo.com"; 
request.ContentLength = postData.Length; 

X509Certificate2Collection certCollect = new X509Certificate2Collection(); 
X509Certificate2 cert = new X509Certificate2(@"C:\a\cert.pfx", "password"); 

certCollect.Add(cert); 
request.ClientCertificates = certCollect; 

using (Stream writeStream = request.GetRequestStream()) { 
    writeStream.Write(postData, 0, postData.Length); } 

WebResponse webResponse = request.GetResponse(); 
string output = new StreamReader(webResponse.GetResponseStream()).ReadToEnd(); 

LogEntry.Write("Recieved : " + output); 
return output; 

violinista de salida (en bruto)

POST https://../Upload.asp?b_customerId=%5BO/M1234%5D HTTP/1.1 
Content-Type: multipart/form-data; boundary=vxvxv 
Host: www.foo.com 
Content-Length: 5500 
Expect: 100-continue 
Connection: Keep-Alive 

--vxvxv 
Content-disposition: form-data; name="File1"; 
filename="provideTest.xml" 
Content-type: text/xml 
<?xml version="1.0" encoding="UTF-8"?> 
...SNIP... 
</bat:Batch> 
--vxvxv-- 
+0

Lo primero que viene a la mente es que su nombre de archivo está en una nueva línea que no debería ser. No se sabe si esto causará el error mencionado, pero probablemente confundirá mucho las cosas al menos. – Chris

+0

Bastante seguro de que eso lo invalidaría. – kamranicus

+0

Lo intenté sin la nueva línea. Mismo resultado –

Respuesta

3

tengo blogged de una forma de cargar varios archivos usando un cliente Web y la posibilidad de enviar parámetros también. Aquí está el código correspondiente:

public class UploadFile 
{ 
    public UploadFile() 
    { 
     ContentType = "application/octet-stream"; 
    } 
    public string Name { get; set; } 
    public string Filename { get; set; } 
    public string ContentType { get; set; } 
    public Stream Stream { get; set; } 
} 

y luego un método para realizar la carga:

public byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values) 
{ 
    var request = WebRequest.Create(address); 
    request.Method = "POST"; 
    var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo); 
    request.ContentType = "multipart/form-data; boundary=" + boundary; 
    boundary = "--" + boundary; 

    using (var requestStream = request.GetRequestStream()) 
    { 
     // Write the values 
     foreach (string name in values.Keys) 
     { 
      var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); 
      requestStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine)); 
      requestStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine); 
      requestStream.Write(buffer, 0, buffer.Length); 
     } 

     // Write the files 
     foreach (var file in files) 
     { 
      var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); 
      requestStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine)); 
      requestStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine)); 
      requestStream.Write(buffer, 0, buffer.Length); 
      file.Stream.CopyTo(requestStream); 
      buffer = Encoding.ASCII.GetBytes(Environment.NewLine); 
      requestStream.Write(buffer, 0, buffer.Length); 
     } 

     var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--"); 
     requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length); 
    } 

    using (var response = request.GetResponse()) 
    using (var responseStream = response.GetResponseStream()) 
    using (var stream = new MemoryStream()) 
    { 
     responseStream.CopyTo(stream); 
     return stream.ToArray(); 
    } 
} 

que podría ser utilizado de esta manera:

using (var stream1 = File.Open("test.txt", FileMode.Open)) 
using (var stream2 = File.Open("test.xml", FileMode.Open)) 
using (var stream3 = File.Open("test.pdf", FileMode.Open)) 
{ 
    var files = new[] 
    { 
     new UploadFile 
     { 
      Name = "file", 
      Filename = "test.txt", 
      ContentType = "text/plain", 
      Stream = stream1 
     }, 
     new UploadFile 
     { 
      Name = "file", 
      Filename = "test.xml", 
      ContentType = "text/xml", 
      Stream = stream2 
     }, 
     new UploadFile 
     { 
      Name = "file", 
      Filename = "test.pdf", 
      ContentType = "application/pdf", 
      Stream = stream3 
     } 
    }; 

    var values = new NameValueCollection 
    { 
     { "key1", "value1" }, 
     { "key2", "value2" }, 
     { "key3", "value3" }, 
    }; 

    byte[] result = UploadFiles("http://localhost:1234/upload", files, values); 
} 
+0

Eso funcionó. Te da la recompensa. Para puntos de bonificación, ¿podría explicar por qué el suyo funcionó y el mío no? Noté que usaste "application/octet-stream" donde utilicé el texto. Tampoco parece configurar la duración del contenido. –

0

Ésta no será una respuesta completa , pero podría ver usar un socket en lugar de WebRequest y realizar la solicitud HTTP usted mismo. Parece que el controlador multiparte en su servidor no cumple y espera que la solicitud sea la misma que la de IE6, por lo que emularlo sería el mejor enfoque.

4

Creo que tienes dos problemas potenciales:

1) La URL que va a enviar el parámetro de formatos b_CustomerId de manera diferente a la implementación IE6. Si el sitio al que se dirige no espera un valor codificado en HTML, podría ser muy fácilmente el origen del mensaje de error.

Su solicitud:

Upload.asp?b_customerId=%5BO/M1234%5D 

La solicitud IE6:

Upload.asp?b_customerId=[O/M1234] 

Con el fin de solucionar este problema, puede crear una nueva URL de una sobrecarga de la Uri class constructor que ha sido marcada como obsoleta , pero aún funciona correctamente Esta sobrecarga le permite especificar que la cadena ya se ha escapado en el segundo parámetro.

Para utilizar este constructor, cambiar esta línea:

request = (HttpWebRequest)WebRequest.Create(url); 

a esto:

request = (HttpWebRequest)WebRequest.Create(new Uri(url, true)); 

2) La etiqueta de contenido-disposición no está formateada de la misma manera en su solicitud, ya que está en la solicitud IE6.

Su solicitud:

Content-disposition: form-data; name="File1"; 
filename="provideTest.xml" 

IE6 solicitud:

Content-disposition: form-data; name=”File1”; filename=”noColonsSpacesOrAmpersandsInHere” 

Esto se puede resolver cambiando estas dos líneas:

"Content-disposition: form-data; name=\"File1\";" + Environment.NewLine + 
"filename=\"provideTest.xml\"" + Environment.NewLine + 

a:

"Content-disposition: form-data; name=\"File1\"; " + 
"filename=\"provideTest.xml\"" + Environment.NewLine + 
+0

¿Cómo se detiene la codificación de [O/M1234]? No pude encontrar una forma con las clases que estoy usando –

+0

@TomSquires: He actualizado la respuesta con detalles adicionales sobre cómo se puede hacer esto (sí se verificó a través de Fiddler que pasa la cadena sin guardar). –

+0

Curiosamente, da el mismo error a pesar de dar una salida exactamente igual a la que se cita en la documentación. Sin embargo, el método de Darvin funcionó. (a pesar de no parecerse a la documentación). Gracias por tu ayuda. –

Cuestiones relacionadas