この記事で解説すること
C#での複数コンテンツのPost方法を実例付きで解説する。
(複数コンテンツというのは、例えば、画像データとその名前の2つなどの事です。)
複数コンテンツのHTTP POSTの実現方法
以下を使うと複数コンテンツのPOSTが行えます。
-
System.Net.Http.HttpClientのPostAsync(Uri, HttpContent)メソッド
- あるいは、PostAsync(uri, HttpContent, fileName)メソッド
- System.Net.Http.MultipartFormDataContect(HttpContentの派生クラス)
要は、MultipartFromDataContenctにデータを追加していき、HttpClientのPostAsyncメソッドの引数として渡すだけです。(MultipartFormDataContentはHttpContentクラスを継承している)
実践-条件
それではやり方の一例を見ていきます。
今回は、以下のコンテンツをPostで送りたいとします。
Postで送るもの
- 画像データと、その名前を一度にPostする
- 画像データ(image):バイナリデータ
- データ名(name):"hogehoge"
Post結果の確認方法
今回の例では、Post結果の確認にhttpbinを使わせてもらいます。
httpbinは、指定のURLにHTTPリクエストを送ると、送信されたパラメータなどの情報をレスポンスとして返してくれるWebサービス&ソフトウェアです。
以下のJsonがPostのResponseとして返ってくれば成功
今回の場合は、http://httpbin.org/post にPOSTリクエストを送り、以下のようなJSONがReponseとして返ってくれば成功です。
確認するポイントは2つです。
- "files"内の"image"に指定したデータ(今回だと画像をバイト配列として送るのでバイト配列)が入っているかどうか
- "form"内の"name"に指定した名前(hogehoge)が入っているどうか
{
"args": {},
"data": "",
"files": {
"image": "(~byteの羅列がここに入る。長いので省略~)"
},
"form": {
"name": "hogehoge"
},
"headers": {
"Content-Length": "13515",
"Content-Type": "multipart/form-data; boundary="5cc407cc-3e4e-4d4a-8f67-fd2f29436423"",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-5fc1ad93-3233ba1c3f705dd867fdf9c9"
},
"json": null,
"origin": "126.99.210.176",
"url": "http://httpbin.org/post"
}
実行環境
- Windows10
- C#8.0 (.NET Core3.1)
実践
本題のコードが以下です。
// MultipartFormDataContentのインスタンスをつくる。
using MultipartFormDataContent multiContent = new MultipartFormDataContent();
// コンテンツを、それぞれ専用の形式でインスタンス化する。
// imageBytes変数には本当は画像をバイナリ化したものが代入されている想定。
// ここでは簡単のため適当なバイナリを入れておく。
using ByteArrayContent imageContent = new ByteArrayContent(new byte[4] { 0, 1, 2, 3 });
using StringContent nameContent = new StringContent("hogehoge");
// 専用の形式にしたコンテンツを、MultipartFormDataContentにAddしていく。
multiContent.Add(imageContent, "image", "imageData");
multiContent.Add(nameContent, "name");
// HttpClientでPostする。
// (本当はHttpClientは都度インスタンスを生成するのではなく、アプリケーション内で使いまわしたほうがよい。)
using HttpClient client = new HttpClient();
var uri = new Uri("http://httpbin.org/post");
var msg = await client.PostAsync(uri, multiContent );
// Responseの表示
var responseContent = await msg.Content.ReadAsStringAsync();
Console.WriteLine($"{responseContent}");
コードについて解説していきます。
- MultipartFormDataContentのインスタンスをつくる
// MultipartFormDataContentのインスタンスをつくる。
using MultipartFormDataContent multiContent = new MultipartFormDataContent();
ここは特に解説の必要もないと思います。
MultipartFormDataContentの派生大元であるHttpContentクラスはIDisposableを継承しているので、usingをつけて勝手に開放してくれるようにしておきます。
(この記事の趣旨とは関係ないですが、C#8.0から、using変数宣言により、その変数のスコープに基づいて自動開放してくれるようになりました。usingステートメントによる多重{}はコードが見にくくなるので、ここではusing変数宣言を使っています。)
- コンテンツをそれぞれ専用の形式でインスタンス化する
// コンテンツを、それぞれ専用の形式でインスタンス化する。
// imageBytes変数には本当は画像をバイナリ化したものが代入されている想定。
// ここでは簡単のため適当なバイナリを入れておく。
using ByteArrayContent imageContent = new ByteArrayContent(new byte[4] { 0, 1, 2, 3 });
using StringContent nameContent = new StringContent("hogehoge");
MultipartFormDataContentに追加していく(もといHttpClientのコンテントとして扱う)ためには、各種コンテンツを専用の形式にしていく必要あります。
専用の形式とは、System.Net.Http.HttpClientクラスの派生クラスのことです。
ここでは、画像データ(それを事前にバイナリ化したもの)と文字列をそれぞれHttpContent化します。画像データはByteArrayContentクラス、文字列はStringContentクラスでHttpContent化します。(ここでは結果が見やすいよう画像データには適当なバイナリをいれてます。)
この部分は送りたいデータの形式に合わせて変えます。(他にはStreamContentクラスや、JsonContentクラスがあります。詳細はHttpContentクラスのドキュメントを読んでください。)
ちなみに、MultipartFormDataContentクラスももちろんHttpContentクラスの派生クラスです。(正確にはMultipartFormDataContentクラス → MultipartContentクラス → HttpContentクラスという継承関係)
- 専用の形式にしたコンテンツをMultipartFormDataContentにAddしていく
// 専用の形式にしたコンテンツを、MultipartFormDataContentにAddしていく。
multiContent.Add(imageContent, "image", "imageData");
multiContent.Add(nameContent, "name");
上で専用の形式(HttpContentクラスの派生クラス)にしたデータを追加していくだけです。
MultipartFormDataContent.Add(HttpContent, string)メソッドを使って追加していきます。
ここで、画像データと文字列データでは、引数の異なるAdd()メソッドを使っています。
MultipartFormDataContent.Add()メソッドには、引数のとり方が3種類あります。
- HttpContentのみ
- HttpContentとString(HTTPコンテンツの名前)
- HttpContentとStringとString(HTTPコンテンツの名前とコレクションに追加する HTTP コンテンツのファイル名)
1, 2番目の方法だとコンテンツがRequestの"form"に含まれ、3番目の方法だとコンテンツがRequestの"files"に含まれます。
今回は、画像データは"files"に含まれて欲しいので3番目、文字列データは"forms"に含まれて欲しいので2番目のメソッドを使います。なお、3番目の方法の場合は、引数の3つ目に文字列が必要ですがこれは今回の場合何でもよいです。
(ちなみに1番目の方法を使った場合は、コンテンツはform"に含まれ、そのkeyにあたるものがnullとなります。)
- POSTする
// HttpClientでPostする。
// (本当はHttpClientは都度インスタンスを生成するのではなく、アプリケーション内で使いまわしたほうがよい。)
using HttpClient client = new HttpClient();
var uri = new Uri("http://httpbin.org/post");
var msg = await client.PostAsync(uri, multiContent );
// Responseの表示
var responseContent = await msg.Content.ReadAsStringAsync();
Console.WriteLine($"{responseContent}");
通常通りHttpClientのPostAsync()メソッドを使ってPostするだけです。
(上のコードではPostとそのResponseの表示をしています。)
結果
コードを実行すると以下がResponseとして返ってきました。
大丈夫そうですね。
- "files"内の"image"に指定したデータが入っている("\u0000\u0001\u0002\u0003"は1, 2, 3, 4をそれぞれ16進数表記にしたもの)
- "form"内の"name"に指定した名前(hogehoge)が入っている
{
"args": {},
"data": "",
"files": {
"image": "\u0000\u0001\u0002\u0003"
},
"form": {
"name": "hogehoge"
},
"headers": {
"Content-Length": "13515",
"Content-Type": "multipart/form-data; boundary="5cc407cc-3e4e-4d4a-8f67-fd2f29436423"",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-5fc1ad93-3233ba1c3f705dd867fdf9c9"
},
"json": null,
"origin": "126.99.210.176",
"url": "http://httpbin.org/post"
}
まとめ
この記事では、C#での複数コンテンツのPost方法を実例付きで解説しました。
簡単にやり方をまとめると以下です。
- MultipartFormDataContentのインスタンスをつくる
- コンテンツをそれぞれ専用の形式でインスタンス化する
- 専用の形式にしたコンテンツをMultipartFormDataContentにAddしていく
- 追加したい形式によって複数あるAddメソッドを使い分ける
- POSTする