2009-12-09 20 views
12

Sto tentando di caricare un file e un invio con alcuni parametri sul mio sito utilizzando .NET/C#. Dopo aver letto alcuni tutorial che fanno alcuni parametri o un file, ho provato, senza successo, a combinarli. Ecco come provo a farlo:WebRequest POST con file e parametri

WebRequest req = WebRequest.Create(baseURL + "upload"); 
req.Credentials = new NetworkCredential(username, password); 
String boundary = "B0unD-Ary"; 
req.ContentType = "multipart/form-data; boundary=" + boundary; 
req.Method = "POST"; 
((HttpWebRequest)req).UserAgent = "UploadTester v0.1"; 

string postData = "--" + boundary + "\nContent-Disposition: form-data\n"; 
postData += "myId=123&someFk=456"; 
postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n"; 
byte[] byteArray = Encoding.UTF8.GetBytes(postData); 

byte[] filedata = null; 
using (BinaryReader reader = new BinaryReader(File.OpenRead("myfile.pdf"))) 
    filedata = reader.ReadBytes((int)reader.BaseStream.Length); 

req.ContentLength = byteArray.Length + filedata.Length; 
req.GetRequestStream().Write(byteArray, 0, byteArray.Length); 
req.GetRequestStream().Write(filedata, 0, filedata.Length); 

WebResponse response = req.GetResponse(); 
Stream data = response.GetResponseStream(); 
StreamReader sReader = new StreamReader(data); 
String sResponse = sReader.ReadToEnd(); 
response.Close(); 

Quando eseguire, ottengo un'eccezione 500, dicendo "sezione Intestazione ha più di 10240 bnytes (forse non è correttamente terminata)" e Wireshark mi informa che il la richiesta inviata era un pacchetto malformato, in cui il multipart MIME era malformato.

Ci sono probabilmente diversi problemi qui, quindi per favore fatemelo sapere tutti i problemi si possono avvistare

Aggiornamento:. Separare MIME da C#/NET, ho generato un thread qui: https://stackoverflow.com/questions/1880002/error-in-mime-packet-for-http-post

Aggiornamento 2: Quindi il back-end ha effettivamente problemi con la lunghezza del contenuto, dicendo che la quantità di byte disponibili per la lettura è inferiore alla lunghezza del contenuto dichiarato. MA! Se riduco la lunghezza del contenuto in req.ContentLength di conseguenza, non ho una dimensione del buffer abbastanza grande per l'invio dei dati. Eventuali suggerimenti?

Update 3: In realtà, sembra che l'intestazione ha una troppo grande rispetto alle dimensioni quantità di dati che contiene

+0

Se si utilizza .NET> = 4.0, saltare alla mia risposta per un modo più semplice per farlo. – Joshcodes

risposta

11

Il problema è che vi state perdendo un '\ n'. La seguente riga:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n"; 

dovrebbe essere:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n\n"; 

E questa linea:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n" 

manca un '\ n' prima 'Content-Type'. Dovrebbe essere:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\"\nContent-Type: application/pdf\n\n" 
+3

Grazie per averlo indicato. Dopo 15 ore di debug, ho trovato il problema principale: il motore .NET traduce tutte le mie newline in CR + Newline, scrivendo così più byte di quanti ne ho specificato nella lunghezza del contenuto. Quindi, per chiunque abbia un problema simile in futuro: sostituire tutte le newline con CR + newline (\ n a \ r \ n) – niklassaers

+0

quando uso questo sto diventando Multipart: il limite finale è previsto? Qualche idea su come risolvere quel problema? –

1

Credo che il problema immediato è una mancata corrispondenza tra il dichiarato e la lunghezza effettiva.

Dove hai calcolato male non sono sicuro, ma se ricordo bene la lunghezza dovrebbe includere ogni byte della risposta (comprese le intestazioni) tranne la prima riga.

A dire il vero vorrei costruire una semplice pagina HTML per generare il messaggio che si desidera ed esaminato il post con violinista (o Firebug)

+0

Ah, grazie, è un buon suggerimento. È un peccato che devo farlo a mano. Sono sicuro che migliaia di persone hanno scritto codice molto simile a questo, sarebbe stato più semplice con una libreria standard. – niklassaers

+0

Hmm, ma la lunghezza del contenuto è impostata correttamente su 129597 byte, non ovunque vicino a 10240.: -I – niklassaers

+0

Invece di scrivere sul flusso della richiesta, lo scrivo in un filestream, e vedo quanti byte ci sono, e assicurati che la lunghezza del contenuto corrisponde. Oppure, in alternativa, scrivere in un MemoryStream, quindi è possibile eseguire un memoryStream.ToArra() e ottenere la lunghezza del contenuto da quello. – feroze

0

tenta di modificare

string postData = "--" + boundary + "\nContent-Disposition: form-data\n"; 

a

string postData = "\n\n--" + boundary + "\nContent-Disposition: form-data\n\n"; 

E meglio anche sostituire tutti i \ n a \ r \ n. Almeno le prime due nuove righe hanno funzionato per me risolvendo il problema "La sezione intestazione ha più di 10240 byte (forse non è terminata correttamente)".

e questo codice non sembra corretta:

postData += "myId=123&someFk=456"; 

Il mio codice Objective-C per iPhone che sto usando e che funziona ora assomiglia a questo:

NSMutableData *reqData = [NSMutableData data]; 
NSURL *encUrl; 
encUrl = [NSURL URLWithString:[NSString url]; 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:encUrl]; 
request.HTTPMethod = @"POST"; 
request.timeoutInterval = kServerConnectionTimeout; 
    NSString *stringBoundary = [NSString stringWithString:@"Multipart-Boundary"]; // TODO - randomize this 
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=\"%@\"",stringBoundary]; 
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; 

[reqData appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
for (id key in [self.parameters allKeys]) 
{ 
    if (![key isEqualToString:@"image"]) 
    { 
     NSString *val = [self.parameters objectForKey:key]; 
     if (val != nil) 
     { 
      [reqData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n",key] dataUsingEncoding:NSUTF8StringEncoding]]; 
      [reqData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
      [reqData appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: 8bit\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
      [reqData appendData:[[NSString stringWithFormat:@"%@",val] dataUsingEncoding:NSUTF8StringEncoding]]; 
      [reqData appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
     } 
    } 
} 

// send binary part last 
if ([self.parameters objectForKey:@"image"]) 
{ 
    NSString *key = @"image"; 
    NSData *imageData = [self.parameters objectForKey:key]; 
    if (imageData != nil) 
    { 
     [reqData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\";filename=\"avatar.png\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [reqData appendData:[[NSString stringWithFormat:@"Content-Type: image/png\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 

     [reqData appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: binary\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [reqData appendData:imageData]; 
     [reqData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 
    } 
} 
NSString * dataLength = [NSString stringWithFormat:@"%d", [reqData length]]; 
[request addValue:dataLength forHTTPHeaderField:@"Content-Length"]; 

request.HTTPBody = reqData; 
NSLog(@"postBody=%@", [[NSString alloc] initWithData:reqData encoding:NSASCIIStringEncoding]); 

Spero che questo aiuti qualcuno.