48

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 = "khalid@home.com",
                        To = new[] { "me@test.com", "you@test.com" },
                        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 }
    );

}
4

4 に答える 4

12

これは、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(),
                    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<HttpResponseMessage> message = client.PostAsync("http://api.brightcove.com/services/post", content);

            var input = message.Result.Content.ReadAsStringAsync();
            Console.WriteLine(input.Result);
            Console.Read();
        }
    }
}
于 2015-01-30T18:51:13.613 に答える
6

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

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

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

RFC ドキュメントMSDN ドキュメントを読んMultipartFormDataContentで、MultipartContent. しかし、私はまだこれをテストしていません。

于 2013-08-05T14:37:39.367 に答える