2012-06-15 9 views
8

Desidero caricare il file su un host utilizzando la classe WebClient. Voglio anche passare alcuni valori che dovrebbero essere visualizzati nell'array $ _POST sulla parte server (PHP). Voglio farlo con una connessione codiceUploadFile con valori POST da WebClient

Ho usato muggito

using (WebClient wc = new WebClient()) 
{ 
    wc.Encoding = Encoding.UTF8; 
    NameValueCollection values = new NameValueCollection(); 
    values.Add("client", "VIP"); 
    values.Add("name", "John Doe"); 
    wc.QueryString = values; // this displayes in $_GET 
    byte[] ans= wc.UploadFile(address, dumpPath); 
} 

Se ho usato proprietà QueryString, i valori visualizzati in $ _GET array.But voglio inviarlo per metodo post

+0

domanda simile qui http: // StackOverflow. it/questions/2950292/how-to-upload-multiple-files-using-webclient-uploadfile-uploadvalues-in-c Potresti voler controllare le risposte –

risposta

30

Non c'è niente di built-in che ti permetta di farlo. Ho blogged su un'estensione che potresti usare. Qui ci sono le classi rilevanti:

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

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

e ora si potrebbe usare nella vostra applicazione:

using (var stream = File.Open(dumpPath, FileMode.Open)) 
{ 
    var files = new[] 
    { 
     new UploadFile 
     { 
      Name = "file", 
      Filename = Path.GetFileName(dumpPath), 
      ContentType = "text/plain", 
      Stream = stream 
     } 
    }; 

    var values = new NameValueCollection 
    { 
     { "client", "VIP" }, 
     { "name", "John Doe" }, 
    }; 

    byte[] result = UploadFiles(address, files, values); 
} 

Ora nel tuo script PHP è possibile utilizzare il $_POST["client"], $_POST["name"] e $_FILES["file"].

+0

quali sarebbero i passaggi per rendere questo asincrono con indicazione di avanzamento? – Pbirkoff

+0

Le funzioni sincrone su HttpWebClient devono essere sostituite con le controparti asincrone: Begin/EndGetRequestStream, Begin/EndGetResponse, ... –

+0

Grazie per questo codice! Se si utilizza MVC 4, è possibile ottenere questa eccezione: "Fine inattesa del flusso multipart MIME. Il messaggio multipart MIME non è completo. ' C'è un bug all'interno del framework (http://aspnetwebstack.codeplex.com/discussions/354215) ed è necessario aggiungere una nuova riga all'ultimo limite: var boundaryBuffer = Encoding.ASCII.GetBytes (boundary + "-" + Environment.NewLine); –

3

Se qualcuno vuole usare @ soluzione Darin-Dimitrov s in un modello asincrono con la segnalazione progresso, questo è il modo di andare (per NET 4.0):

public void UploadFileAsync(NameValueCollection values, Stream fileStream) 
{ 
    //to fire events on the calling thread 
    _asyncOperation = AsyncOperationManager.CreateOperation(null); 
    var ms = new MemoryStream(); 
    //make a copy of the input stream in case sb uses disposable stream 
    fileStream.CopyTo(ms); 
    //you cannot set stream position often enough to zero 
    ms.Position = 0; 

    Task.Factory.StartNew(() => 
    { 
     try 
     { 
      const string contentType = "application/octet-stream"; 

      var request = WebRequest.Create(_url); 
      request.Method = "POST"; 
      var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo); 
      request.ContentType = "multipart/form-data; boundary=" + boundary; 
      boundary = "--" + boundary; 

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

      // Write the file 
      buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); 
      dataStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"file\"; filename=\"file\"{Environment.NewLine}"); 
      dataStream.Write(buffer, 0, buffer.Length); 
      buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", contentType, Environment.NewLine)); 
      dataStream.Write(buffer, 0, buffer.Length); 
      ms.CopyTo(dataStream); 
      buffer = Encoding.ASCII.GetBytes(Environment.NewLine); 
      dataStream.Write(buffer, 0, buffer.Length); 

      buffer = Encoding.ASCII.GetBytes(boundary + "--"); 
      dataStream.Write(buffer, 0, buffer.Length); 


      dataStream.Position = 0; 
      //IMPORTANT: set content length to directly write to network socket 
      request.ContentLength = dataStream.Length; 
      var requestStream = request.GetRequestStream(); 

      //Write data in chunks and report progress 
      var size = dataStream.Length; 
      const int chunkSize = 64 * 1024; 
      buffer = new byte[chunkSize]; 
      long bytesSent = 0; 
      int readBytes; 
      while ((readBytes = dataStream.Read(buffer, 0, buffer.Length)) > 0) 
      { 
       requestStream.Write(buffer, 0, readBytes); 
       bytesSent += readBytes; 

       var status = "Uploading... " + bytesSent/1024 + "KB of " + size/1024 + "KB"; 
       var percentage = Tools.Clamp(Convert.ToInt32(100 * bytesSent/size), 0, 100); 
       OnFileUploaderProgressChanged(new FileUploaderProgessChangedEventArgs(status, percentage)); 
      } 

      //get response 
      using (var response = request.GetResponse()) 
      using (var responseStream = response.GetResponseStream()) 
      using (var stream = new MemoryStream()) 
      { 
       // ReSharper disable once PossibleNullReferenceException - exception would get catched anyway 
       responseStream.CopyTo(stream); 
       var result = Encoding.Default.GetString(stream.ToArray()); 
       OnFileUploaderCompleted(result == string.Empty 
        ? new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Failed) 
        : new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Ok)); 
      } 
     } 
     catch (Exception) 
     { 
      OnFileUploaderCompleted(new FileUploaderCompletedEventArgs(FileUploaderCompletedResult.Failed)); 
     } 
    }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); 
}