2013-08-05 21 views
33

Tôi đang cố gắng thực hiện một biểu mẫu nhiều bài đăng bằng cách sử dụng HttpClient trong C# và tìm mã sau không hoạt động.HttpClient Multipart Form Đăng trong C#

Chú ý:

var jsonToSend = JsonConvert.SerializeObject(json, Formatting.None, new IsoDateTimeConverter()); 
var multipart = new MultipartFormDataContent(); 
var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json"); 

multipart.Add(body); 
multipart.Add(new ByteArrayContent(File.ReadAllBytes("test.txt")), "test", "test.txt"); 

var httpClient = new HttpClient(); 
var response = httpClient.PostAsync(new Uri("http://localhost:55530"), multipart).Result; 

Full Chương trình:

namespace CourierMvc.Worker 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      while (true) 
      { 
       Console.WriteLine("Hit any key to make request."); 
       Console.ReadKey(); 

       try 
       { 
        var request = new RestRequest(Method.POST) 
        { 
         Resource = "http://localhost:55530" 
        }; 

        var json = new CourierMessage 
        { 
         Id = Guid.NewGuid().ToString(), 
         Key = "awesome", 
         From = "[email protected]", 
         To = new[] { "[email protected]", "[email protected]" }, 
         Subject = "test", 
         Body = "body", 
         Processed = DateTimeOffset.UtcNow, 
         Received = DateTime.Now, 
         Created = DateTime.Now, 
         Sent = DateTime.Now, 
         Links = new[] { new Anchor { Link = "http://google.com" }, new Anchor { Link = "http://yahoo.com" } } 
        }; 

        var jsonToSend = JsonConvert.SerializeObject(json, Formatting.None, new IsoDateTimeConverter()); 
        var multipart = new MultipartFormDataContent(); 
        var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json"); 

        multipart.Add(body); 
        multipart.Add(new ByteArrayContent(File.ReadAllBytes("test.txt")), "test", "test.txt"); 

        var httpClient = new HttpClient(); 
        var response = httpClient.PostAsync(new Uri("http://localhost:55530"), multipart).Result; 

       } 
       catch (Exception e) 
       { 
        Console.WriteLine(e); 
       } 
      } 
     } 
    } 
} 

tôi thực sự không có ý tưởng tại sao nó không hoạt động. Tôi nhận được các tập tin để gửi đến điểm cuối, nhưng cơ thể (json) không bao giờ đạt được điều đó. Tôi có làm điều gì sai?

Server Side Mã Yêu cầu:

namespace CourierMvc.Controllers 
{ 
    public class HomeController : Controller 
    { 
     // 
     // GET: /Home/ 

     public ActionResult Index() 
     { 
      return Content("Home#Index"); 
     } 


     [ValidateInput(false)] 
     public ActionResult Create(CourierMessage input) 
     { 
      var files = Request.Files; 

      return Content("OK"); 
     } 

    } 
} 

Route Config:

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Create", id = UrlParameter.Optional } 
    ); 

} 
+1

Tại sao ai đó bỏ phiếu này? Tôi đã cung cấp mã và giải thích những gì tôi đang cố gắng làm. Đó là một tuyên bố rõ ràng. –

+0

Có thể hữu ích nếu bạn cũng hiển thị mã phía máy chủ để chúng tôi có thể thấy cách bạn đang cố đọc nó. –

+0

Mã phía máy chủ chỉ là một điểm cuối ASP.NET MVC, với mô hình làm kiểu đầu vào. Không có gì ngoạn mục ở đó, nhưng tôi đặt nó lên để cho thấy không có shenanigans. –

Trả lời

4

Vì vậy, vấn đề tôi thấy là rằng thông điệp MultipartFormDataContent yêu cầu sẽ luôn thiết lập các kiểu nội dung của yêu cầu "multipart/form-data". Mã hóa json và đặt nó vào yêu cầu chỉ "trông" giống như mô hình kết dính dưới dạng chuỗi.

lựa chọn của bạn là:

  • có phương pháp hành động MVC của bạn nhận được một chuỗi và deserialize thành đối tượng của bạn
  • bài mỗi thuộc tính của mô hình của bạn như là một phần hình thức
  • tạo ra một mô hình tùy chỉnh chất kết dính đó sẽ xử lý yêu cầu của bạn.
  • Chia nhỏ hoạt động thành hai bài đăng, trước tiên gửi siêu dữ liệu json, người kia gửi tệp. Phản hồi từ máy chủ sẽ gửi một số id hoặc khóa để tương quan hai yêu cầu.

Đọc qua the RFC documentthe MSDN documentation bạn có thể làm điều này, nếu bạn thay thế MultipartFormDataContent với MultipartContent. Nhưng tôi chưa thử nghiệm điều này.

+0

Đã thử MultipartContent và điều đó không hoạt động. Tôi thực sự không muốn thực hiện đề xuất đầu tiên của bạn, nhưng có vẻ như nó sẽ xảy ra. –

+0

Bạn đúng về HttpClient muốn thêm nội dung chuỗi dưới dạng giá trị biểu mẫu thay vì chỉ đăng nó như một phần khác của bài đăng. Không chắc chắn nếu đây là một lỗi trong HttpClient hoặc một sự hiểu lầm cơ bản về phía tôi. –

+0

Vâng, thông thường khi bạn phải đăng một tập tin, kiểu nội dung là 'multipart/form-data', giống như bất kỳ kiểu dữ liệu nào, bài viết chỉ đơn giản là một cặp tuần tự giá trị khóa. Khi bạn thêm json của bạn, nó chỉ là một cặp khác, không được xem như là một đối tượng được tuần tự hóa cho mô hình kết dính trong MVC. – Jay

40
public class CourierMessage 
{ 
    public string Id { get; set; } 
    public string Key { get; set; } 
    public string From { get; set; } 
    public string Subject { get; set; } 
    public string Body { get; set; } 
    public DateTimeOffset Processed { get; set; } 
    public DateTime Received { get; set; } 
    public DateTime Created { get; set; } 
    public DateTime Sent { get; set; } 
    public HttpPostedFileBase File { get; set; } 
} 




while (true) 
{ 
    Console.WriteLine("Hit any key to make request."); 
    Console.ReadKey(); 

    using (var client = new HttpClient()) 
    { 
     using (var multipartFormDataContent = new MultipartFormDataContent()) 
     { 
      var values = new[] 
      { 
       new KeyValuePair<string, string>("Id", Guid.NewGuid().ToString()), 
       new KeyValuePair<string, string>("Key", "awesome"), 
       new KeyValuePair<string, string>("From", "[email protected]") 
       //other values 
      }; 

      foreach (var keyValuePair in values) 
      { 
       multipartFormDataContent.Add(new StringContent(keyValuePair.Value), 
        String.Format("\"{0}\"", keyValuePair.Key)); 
      } 

      multipartFormDataContent.Add(new ByteArrayContent(File.ReadAllBytes("test.txt")), 
       '"' + "File" + '"', 
       '"' + "test.txt" + '"'); 

      var requestUri = "http://localhost:5949"; 
      var result = client.PostAsync(requestUri, multipartFormDataContent).Result; 
     } 
    } 
} 

enter image description here

+0

Thử thêm một danh sách phức tạp vào ví dụ của bạn và xem nó có hoạt động không. Theo một danh sách phức tạp, tôi có nghĩa là Danh sách các đối tượng neo. Tôi thấy rằng bạn đã loại bỏ chúng ... Tôi không nghĩ rằng đó là một tai nạn trên một phần của bạn :) –

+0

@ KhalidAbuhakmeh Tôi đã không thêm các thuộc tính còn lại như tôi chỉ muốn cung cấp cho bạn một ví dụ đó là làm việc dựa trên ban đầu của bạn câu hỏi. –

+1

Cách duy nhất bạn có thể Đăng một đối tượng phức tạp (Danh sách) theo cách này là nếu bạn sắp xếp chúng thành một danh sách được phân cách bằng dấu phẩy hoặc vào một blob JSON. Đây vẫn là một giải pháp tốt. –

5

Đây là một ví dụ về làm thế nào để gửi chuỗi và tập tin dòng với HttpClient sử dụng MultipartFormDataContent. Nội dung-Bố trí và Loại Nội dung cần phải được chỉ định cho mỗi HTTPContent:

Đây là ví dụ của tôi. Hy vọng điều này sẽ giúp:

 

private static void Upload() 
     { 

      using (var client = new HttpClient()) 
      { 
       client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service"); 

       using (var content = new MultipartFormDataContent()) 
       { 
        var path = @"C:\B2BAssetRoot\files\596086\596086.1.mp4"; 

        string assetName = Path.GetFileName(path); 

        var request = new HTTPBrightCoveRequest() 
         { 
          Method = "create_video", 
          Parameters = new Params() 
           { 
            CreateMultipleRenditions = "true", 
            EncodeTo = EncodeTo.Mp4.ToString().ToUpper(), 
            Token = "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg..", 
            Video = new Video() 
             { 
              Name = assetName, 
              ReferenceId = Guid.NewGuid().ToString(), 
              ShortDescription = assetName 
             } 
           } 
         }; 

        //Content-Disposition: form-data; name="json" 
        var stringContent = new StringContent(JsonConvert.SerializeObject(request)); 
        stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\""); 
        content.Add(stringContent, "json"); 


        FileStream fs = File.OpenRead(path); 

        var streamContent = new StreamContent(fs); 
        streamContent.Headers.Add("Content-Type", "application/octet-stream"); 
        streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\""); 
        content.Add(streamContent, "file", Path.GetFileName(path)); 

        //content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 



        Task message = client.PostAsync("http://api.brightcove.com/services/post", content); 

        var input = message.Result.Content.ReadAsStringAsync(); 
        Console.WriteLine(input.Result); 
        Console.Read(); 
       } 
      } 
     } 

+0

Cảm ơn bạn. Điều này đã cứu tôi sau một giờ tìm kiếm tốt cách đặt dữ liệu vào biểu mẫu http của yêu cầu: stringContent.Headers.Add ("Content-Disposition", "form-data; name = \" json \ ""); Bây giờ đối tượng Json của tôi là siêu dễ dàng để acces. this.Request.Form ["json"]; –

+0

"Nội dung-Bố trí và Loại Nội dung cần được chỉ định cho mỗi HTTPContent" -> điều này đã lưu tôi –