質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.69%

【.NET】【C#】【Xamarin】HttpClient における MultipartFormDataContent

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,159

Daiki-Kawanuma

score 27

【実装環境】

  • Xamarin.Forms 2.5.0.122203
  • PCL Profile7
  • Android の HttpClient を使用
     

【やりたいこと】
Xamarin で、HttpClient を用いてマルチパートなデータを送信したいです。
実現したいのは以下のcurlになります。

curl -v -H "Content-Type:multipart/form-data" 
-F "parameters={\"communityDetail\":\"world\",\"communityName\":\"hello\",\"communityTags\":\"#hello\"};type=application/json" 
-F "file=@/Users/Daiki/Desktop/cat06.jpg" 
https://app-server.mybluemix.net/api/v1/communities


 
【試したコード】
以下のコードを試しました。

var content = new MultipartFormDataContent();
content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

var imageContent = new ByteArrayContent(imageByteArray);
imageContent.Headers.ContentDisposition =
    new ContentDispositionHeaderValue("form-data") {Name = "\"file\""};
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(imageContent, "file");

var bytes = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(community));
var byteContent = new ByteArrayContent(bytes);
byteContent.Headers.ContentDisposition =
   new ContentDispositionHeaderValue("form-data") {Name = "\"parameters\""};
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Add(byteContent, "parameters");

var response = await _client.PostAsync("api/v1/communities", content);
Debug.WriteLine(response.StatusCode + ", " + response.Content.ReadAsStringAsync().Result);

結果、以下のレスポンスが返っています(サーバーサイドは Spring Boot)。

InternalServerError, {"timestamp":1521470466137,"status":500,"error":"Internal Server Error","exception":"org.springframework.web.multipart.MultipartException","message":"Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found","path":"/api/v1/communities"}


 
マルチパートなデータが正しく送れていないように見えますが、何か間違っているところがありますでしょうか?
ご教授のほど、よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ちょろっと試してみましたが、サンプルのコードは全体的におかしいです。

  • 方やMediaTypeHeaderValue.Parse("multipart/form-data")の記述、
    方やnew MediaTypeHeaderValue("application/json")の記述、統一されてないのが気になる
  • インスタンスをJson化してByteArrayContentとして宣言しているのはいいが、その場合MediaTypeHeaderValueはJsonではなくなるのでは?
    Jsonを指定するならByteArrayContentではなくStringContentを使うのが適当
  • ✕:ご教授
    ◯:ご教示

とりあえずローカルでWebAPI立てて送受信テストしてみましたが、これでHTTP.OKになります。

        static async Task Send()
        {
            var imageByteArray = File.ReadAllBytes(@"C:\work\image.png");
            var community = new { Key = "Test", Name = "Hoge", Desc = "Fuga" };
            using (var _client = new HttpClient())
            {
                var content = new MultipartFormDataContent();
                //content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

                var imageContent = new ByteArrayContent(imageByteArray);
                //imageContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "\"file\"" };
                //imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
                imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
                content.Add(imageContent, "file");

                var bytes = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(community));
                var byteContent = new ByteArrayContent(bytes);
                //byteContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "\"parameters\"" };
                //byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                content.Add(byteContent, "parameters");

                var response = await _client.PostAsync("http://localhost:25980/api/values", content);
                Debug.WriteLine(response.StatusCode + ", " + response.Content.ReadAsStringAsync().Result);
            }
        }

あとは余談ですが、HttpClientはAndroidのものではなく.NET標準です。
なのでタグにあるXamarinも不適当で、たたただ単純にHTTP送信ができないってのが困りごとの本質です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/20 22:47

    ご回答いただきましてありがとうございます。
    理解不足で統一感のないコード、言葉の誤用失礼しました。

    ご回答いただきました内容を元に修正したところ、サーバー側から 200 OK を得ることができました。
    Spring Boot の制約なのか、content.Add(imageContent, "file", "test.jpg"); のようにファイル名を追加しないとエラーになるようです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.69%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる