2012-02-04 34 views
8

Tôi muốn đăng nhiều file và các biến dạng cho một kịch bản CGI, tất cả trong một yêu cầu HTTP. Tôi tin rằng điều này yêu cầu bài đăng HTTP có mã hóa multipart/form-data. Đây là mẫu HTML mẫu gửi thông tin được yêu cầu; Tôi cần gửi cùng một thông tin thông qua ứng dụng:bài viết nhiều tập tin và các giá trị hình thức sử dụng .NET (giao diện điều khiển ứng dụng)

<form action="/process.php" enctype="multipart/form-data" method="post"> 
<input type="text" name="foo" value="bar"> 
<input type="text" name="blah" value="baz"> 
<input type="file" name="file1"> 
<input type="file" name="file2"> 
<input type="file" name="file3"> 
</form> 

Xin lưu ý rằng ứng dụng là ứng dụng C# .NET GUI (hoặc bảng điều khiển), không phải là ứng dụng ASP.Net.

+0

bản sao có thể có của [Tải lên tệp với HTTPWebyêu cầu (multipart/form-data)] (http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data) –

Trả lời

17

Tôi đã làm điều này năm ngoái dựa trên một số mã mà tôi đã tìm thấy. Nó hỗ trợ chính xác những gì bạn muốn, cả hai tập tin và giá trị.

Đây là lớp được gọi là HttpForm:

public class HttpForm { 

    private Dictionary<string, string> _files = new Dictionary<string, string>(); 
    private Dictionary<string, string> _values = new Dictionary<string, string>(); 

    public HttpForm(string url) { 
     this.Url = url; 
     this.Method = "POST"; 
    } 

    public string Method { get; set; } 
    public string Url { get; set; } 

    //return self so that we can chain 
    public HttpForm AttachFile(string field, string fileName) { 
     _files[field] = fileName; 
     return this; 
    } 

    public HttpForm ResetForm(){ 
     _files.Clear(); 
     _values.Clear(); 
     return this; 
    } 

    //return self so that we can chain 
    public HttpForm SetValue(string field, string value) { 
     _values[field] = value; 
     return this; 
    } 

    public HttpWebResponse Submit() { 
     return this.UploadFiles(_files, _values); 
    } 


    private HttpWebResponse UploadFiles(Dictionary<string, string> files, Dictionary<string, string> otherValues) { 
     var req = (HttpWebRequest)WebRequest.Create(this.Url); 

     req.Timeout = 10000 * 1000; 
     req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 
     req.AllowAutoRedirect = false; 

     var mimeParts = new List<MimePart>(); 
     try { 
      if (otherValues != null) { 
       foreach (var fieldName in otherValues.Keys) { 
        var part = new MimePart(); 

        part.Headers["Content-Disposition"] = "form-data; name=\"" + fieldName + "\""; 
        part.Data = new MemoryStream(Encoding.UTF8.GetBytes(otherValues[fieldName])); 

        mimeParts.Add(part); 
       } 
      } 

      if (files != null) { 
       foreach (var fieldName in files.Keys) { 
        var part = new MimePart(); 

        part.Headers["Content-Disposition"] = "form-data; name=\"" + fieldName + "\"; filename=\"" + files[fieldName] + "\""; 
        part.Headers["Content-Type"] = "application/octet-stream"; 
        part.Data = File.OpenRead(files[fieldName]); 

        mimeParts.Add(part); 
       } 
      } 

      string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); 

      req.ContentType = "multipart/form-data; boundary=" + boundary; 
      req.Method = this.Method; 

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

      var res = (HttpWebResponse)req.GetResponse(); 

      return res; 
     } catch (Exception ex) { 
      Console.WriteLine(ex.Message); 
      foreach (MimePart part in mimeParts) 
       if (part.Data != null) 
        part.Data.Dispose(); 

      return (HttpWebResponse)req.GetResponse(); 
     } 
    } 

    private class MimePart { 
     private NameValueCollection _headers = new NameValueCollection(); 
     public NameValueCollection Headers { get { return _headers; } } 

     public byte[] Header { get; protected set; } 

     public long GenerateHeaderFooterData(string boundary) { 
      StringBuilder sb = new StringBuilder(); 

      sb.Append("--"); 
      sb.Append(boundary); 
      sb.AppendLine(); 
      foreach (string key in _headers.AllKeys) { 
       sb.Append(key); 
       sb.Append(": "); 
       sb.AppendLine(_headers[key]); 
      } 
      sb.AppendLine(); 

      Header = Encoding.UTF8.GetBytes(sb.ToString()); 

      return Header.Length + Data.Length + 2; 
     } 

     public Stream Data { get; set; } 
    } 
} 

Bạn có thể sử dụng nó như thế này:

var file1 = @"C:\file"; 
var file2 = @"C:\file2"; 

var yourUrl = "http://yourdomain.com/process.php"; 
var httpForm = new HttpForm(yourUrl); 
httpForm.AttachFile("file1", file1).AttachFile("file2", file2); 
httpForm.setValue("foo", "some foo").setValue("blah", "rarrr!"); 
httpForm.Submit(); 

Hãy cho tôi biết nếu nó làm việc cho bạn.

+0

Cực kỳ hữu ích. – AgentFire

1

Tôi phải làm điều tương tự trên một dự án vào năm ngoái. Sau khi một số nhìn xung quanh, tôi thấy điều này:

Upload files with HTTPWebrequest (multipart/form-data)

Câu trả lời thứ hai trong đó nên là những gì bạn đang tìm kiếm. Khi tôi đang cố gắng làm điều này, tôi gặp rắc rối khi nhận được phương pháp chính xác đó để làm việc. Vấn đề là C# .NET không có bất kỳ hỗ trợ nào cho nhiều cặp khóa/giá trị trong POST. Vì vậy, bạn phải tự xây dựng tiêu đề nội dung yêu cầu HTTP. Tôi tin rằng câu trả lời trong liên kết ở trên ghi nó trực tiếp vào luồng yêu cầu. Tôi đã có thể chuyển đổi mã được tìm thấy tại liên kết bên dưới để tạo tiêu đề và sau đó đã ghi các byte vào luồng yêu cầu.

http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/

Mã của tôi trông giống như sau (tôi đã phải sửa đổi nó dưới đây để có thể đọc bởi vì rất nhiều trừu tượng hiện như một phần của toàn bộ dự án, vì vậy nó có thể không được hoàn hảo cú pháp).

public void BuildHeader(string contentType, string filename) 
    { 

     if ((contentType == null) || 
      (contentType.Length == 0)) 
     { 
      contentType = "application/octet-stream"; 
     } 

     // Create the boundary string for the POST message header 
     string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); 

     // Build up the POST message header 
     StringBuilder sb = new StringBuilder(); 

     // The specific format used can be found in the HTTP protocol specs. 
     // The 'name' variable indicates the field-name, and the last variable 
     // added to the string before another boundary is the value for that field. 
     sb.Append("--"); 
     sb.Append(boundary); 
     sb.Append("\r\n"); 
     sb.Append("Content-Disposition: form-data; name=\""); 
     sb.Append("path"); 
     sb.Append("\""); 
     sb.Append("\r\n\r\n"); 
     sb.Append(fileName); 

     sb.Append("--"); 
     sb.Append(boundary); 
     sb.Append("\r\n"); 
     sb.Append("Content-Disposition: form-data; name=\""); 
     sb.Append("contents"); 
     sb.Append("\"; fileName=\""); 
     sb.Append("abc"); 
     sb.Append("\""); 
     sb.Append("\r\n"); 
     sb.Append("Content-Type: "); 
     sb.Append(contentType); 
     sb.Append("\r\n"); 
     sb.Append("\r\n"); 

     using (Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 
     { 
      // Add the file contents to the POST message 
      byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))]; 
      int bytesRead = 0; 
      while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) 
      { 
       sb.Append(ASCIIEncoding.ASCII.GetString(buffer)); 
      } 

      // Get the byte array of the POST message, and its length 
      string totalContents = sb.ToString(); 
      byte[] totalUpload = Encoding.UTF8.GetBytes(totalContents); 
      int length = totalUpload.Length; 
     } 
    } 

Lưu ý rằng điều này chỉ chuẩn bị tiêu đề để tải lên một tệp.

Các vấn đề liên quan