2012-04-26 9 views
51

Tôi có một dịch vụ WebAPI xử lý tải lên từ một hình thức đơn giản, như thế này:ASP.NET WebAPI: làm thế nào để thực hiện một bài nhiều phần dữ liệu với tập tin tải lên sử dụng WebAPI HttpClient

<form action="/api/workitems" enctype="multipart/form-data" method="post"> 
     <input type="hidden" name="type" value="ExtractText" /> 
     <input type="file" name="FileForUpload" /> 
     <input type="submit" value="Run test" /> 
    </form> 

Tuy nhiên, tôi không thể tìm hiểu cách mô phỏng cùng một bài đăng bằng cách sử dụng API HttpClient. Các bit FormUrlEncodedContent là đủ đơn giản, nhưng làm cách nào để thêm nội dung tệp có tên vào bài đăng?

+0

Bạn có nhớ chia sẻ mã ở phía WebApi sử dụng MultipartFormDataContent không? – granadaCoder

Trả lời

107

Sau nhiều thử và sai, đây là mã mà thực sự hoạt động:

using (var client = new HttpClient()) 
{ 
    using (var content = new MultipartFormDataContent()) 
    { 
     var values = new[] 
     { 
      new KeyValuePair<string, string>("Foo", "Bar"), 
      new KeyValuePair<string, string>("More", "Less"), 
     }; 

     foreach (var keyValuePair in values) 
     { 
      content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key); 
     } 

     var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName)); 
     fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") 
     { 
      FileName = "Foo.txt" 
     }; 
     content.Add(fileContent); 

     var requestUri = "/api/action"; 
     var result = client.PostAsync(requestUri, content).Result; 
    } 
} 
+17

Sử dụng StreamContent cho các tệp lớn: var fileContent = new StreamContent (File.OpenRead (tên tệp)); –

+0

Woohoo - Tôi có một vấn đề hoàn toàn khác, nhưng cần thiết để đăng nội dung. Tôi đã có thể sửa đổi để phù hợp với nhu cầu của mình. Cảm ơn rất nhiều!! –

+3

Điều này không phù hợp với tôi. Tôi đã phải thêm dấu ngoặc kép xung quanh tên nội dung, xem: http://stackoverflow.com/questions/15638622/how-to-upload-files-to-asp-net-mvc-4-0-action-running-in -iis-express-with-httpcl/15638623 # 15638623 – deerchao

9

Bạn cần tìm các lớp con khác nhau của HttpContent.

Bạn tạo nội dung http đa dạng và thêm các phần khác nhau vào nó. Trong trường hợp của bạn, bạn có một mảng byte nội dung và hình thức url mã hóa dọc theo dòng của:

HttpClient c = new HttpClient(); 
var fileContent = new ByteArrayContent(new byte[100]); 
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") 
              { 
               FileName = "myFilename.txt" 
              }; 

var formData = new FormUrlEncodedContent(new[] 
              { 
               new KeyValuePair<string, string>("name", "ali"), 
               new KeyValuePair<string, string>("title", "ostad") 
              }); 


MultipartContent content = new MultipartContent(); 
content.Add(formData); 
content.Add(fileContent); 
c.PostAsync(myUrl, content); 
+1

Điều đó không có tác dụng, thật không may, mặc dù tiêu đề 'ContentDisposition' dường như đưa tôi một bước tiến. Nếu tôi sử dụng mã mẫu của bạn, tôi sẽ nhận được một ngoại lệ 'Loại phương tiện không được hỗ trợ'. Tuy nhiên, nếu tôi thay thế 'MultipartContent' bằng' MultipartFormDataContent' thì ngoại lệ sẽ biến mất. Tuy nhiên, trên máy chủ, giá trị của trường ẩn bị thiếu. –

+0

@MichaelTeper Tôi chưa thử nghiệm mã. Tôi sẽ chơi một chút với nó và cập nhật các bài viết, nhưng quan điểm của tôi là để cho bạn thấy một đoạn của những gì bạn cần phải tìm kiếm và không phải là một mã làm việc. – Aliostad

7

Cảm ơn bạn @ Michael Tepper cho câu trả lời của bạn.

Tôi phải gửi tệp đính kèm cho MailGun (nhà cung cấp dịch vụ email) và tôi phải sửa đổi nó một chút để nó chấp nhận tệp đính kèm của tôi.

var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName)); 
fileContent.Headers.ContentDisposition = 
     new ContentDispositionHeaderValue("form-data") //<- 'form-data' instead of 'attachment' 
{ 
    Name = "attachment", // <- included line... 
    FileName = "Foo.txt", 
}; 
multipartFormDataContent.Add(fileContent); 

Đây để tham khảo trong tương lai. Cảm ơn.