web-dev-qa-db-ja.com

C#でのHttpClientマルチパートフォームポスト

C#でHttpClientを使用してマルチパートフォームポストを実行しようとしていますが、次のコードが機能しないことがわかりました。

重要:

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

}
41

したがって、私が見ている問題は、MultipartFormDataContentリクエストメッセージが常にリクエストのコンテンツタイプを「multipart/form-data」に設定することです。 JSONを終了し、それをリクエストに配置すると、モデルバインダーが文字列として「見える」だけです。

オプションは次のとおりです。

  • mvcアクションメソッドに文字列を受け取り、オブジェクトに逆シリアル化します
  • モデルの各プロパティをフォームパーツとして投稿する
  • リクエストを処理するカスタムモデルバインダーを作成します。
  • 操作を2つの投稿に分割し、最初にjsonメタデータを送信し、もう1つがファイルを送信します。サーバーからの応答は、2つの要求を相互に関連付けるためのIDまたはキーを送信する必要があります。

RFCドキュメント および MSDNドキュメント を読むと、MultipartFormDataContentMultipartContentに置き換えると、これを実行できる場合があります。しかし、私はまだこれをテストしていません。

6
Jay
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

51
Matija Grcic

これは、MultipartFormDataContentを使用してHTTPClientで文字列とファイルストリームを投稿する方法の例です。 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()、
トークン= "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg .."、
 Video = new Video()
 {
 Name = assetName、
 ReferenceId = Guid.NewGuid()。ToG ()、
 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"); 
 
 
 
タスクメッセージ= client.PostAsync( "http://api.brigh tcove.com/services/post "、content); 
 
 var input = message.Result.Content.ReadAsStringAsync(); 
 Console.WriteLine(input.Result); 
 Console.Read(); 
} 
} 
} 
 
6
Johnny Chu