2013-08-05 8 views
33

C#でHttpClientを使用してマルチパートフォームの投稿をしようとしていますが、次のコードが動作しないことが判明しました。HttpClient Multipart Form Post in C#

重要:

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; 

全プログラム

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

私は実際にそれが動作しない理由はわかりません。私はファイルをエンドポイントにポストするようにしますが、ボディ(json)はそこに到達しません。私は何か間違っているのですか?

サーバーサイドコード要求:

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

    } 
} 

ルート設定:

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

なぜ誰かがこれを投票しましたか?私はコードを提供し、私がしようとしていることを説明しました。それは明確な声明です。 –

+0

サーバー側のコードも表示すると、読んでみる方法がわかります。 –

+0

サーバーサイドコードは、モデルを入力タイプとしてASP.NET MVCエンドポイントに過ぎません。そこには壮大なものはありませんが、私はそれを置いて、無駄なことがないことを示しています。 –

答えて

4

だから私は見ている問題は、MultipartFormDataContent要求メッセージは常にのコンテンツタイプを設定するということです"multipart/form-data"へのリクエスト。 jsonをエンドコードし、それをリクエストに入れることは、モデルバインダーのように文字列として "見える"だけです。

あなたのオプションは以下のとおりです。

  • は、あなたのMVCアクションメソッドは、フォームの一部
  • としてモデルの各プロパティを文字列を受け取り、あなたのオブジェクト
  • ポストに非直列化していることでしょうカスタムモデルバインダーを作成しますあなたの要求を処理してください。
  • 2つの投稿に操作を分割し、最初にjsonメタデータを送信し、もう1つはファイルを送信します。サーバーからの応答は、2つの要求を関連付けるために、いくつかのIDまたはキーを送信する必要があります。 the RFC documentを通して読むと

the MSDN documentationあなたはMultipartContentMultipartFormDataContentを交換する場合は、これを行うことができるかもしれません。しかし、私はまだこれをテストしていません。

+0

試したMultipartContentが動作しませんでした。私は本当にあなたの最初の提案をしたくありませんが、それが事実になる可能性が高いと考えています。 –

+0

あなたは、HttpClientが文字列コンテンツをフォームの値として追加するだけで、投稿の別の部分として投稿するのではないかと思います。これがHttpClientのバグか、私のところでの基本的な誤解かどうかは不明です。 –

+0

通常、ファイルをポストする必要がある場合、コンテンツタイプは 'multipart/form-data'です。フォームデータ型と同様、ポストは単純にキー値のペアのシリアル化です。あなたのJSONを追加すると、それは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

例に複雑なリストを追加し、それがまだ機能しているかどうかを確認してください。複雑なリストでは、アンカーオブジェクトのリストを意味します。私はあなたがそれらを削除したことを確認します...私はそれがあなたの部分に事故だったとは思わない:) –

+0

@ KhalidAbuhakmeh私はちょうどあなたのイニシャルに基づいて動作している例を提供したいと思ったので、残りのプロパティを追加していない質問。 –

+1

複合オブジェクト(List)をこのように投稿できる唯一の方法は、コンマ区切りリストまたはJSON blobにシリアル化する場合です。これはまだ良い解決策です。 –

5

これは、HTTPClientのはMultipartFormDataContentを使用して文字列とファイルストリームを投稿する方法の例です。 Content-DispositionとContent-TypeをHTTPContentごとに指定する必要があります。

これは私の例です。役に立ったらいいですか?

 

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

ありがとうございます。これは、リクエストのhttpフォームにデータを入れる方法を検索した後、私を助けました。 stringContent.Headers.Add( "Content-Disposition"、 "form-data; name = \" json \ ""); 今、私のJsonオブジェクトは超簡単にアクセスできます。 this.Request.Form ["json"]; –

+0

"各HTTPContentに対してContent-DispositionとContent-Typeを指定する必要があります" - >これが私を保存しました –

関連する問題