by WebSurfer
6. March 2019 14:47
ASP.NET Web API に、フォームデータ name=value の name に C# の識別子に使えない文字が含まれて POST されてくる場合、どのように value を取得するかを書きます。実際にそんなケースはなさそうなので、役に立たない情報かもしれませんが。(笑)

一般的なバインディングの話は先の記事「ASP.NET Web API のバインディング」に書きました。その記事のコードの Post メソッドに "AAA:Id=6&AAA:Name=ガッチャマンの息子" という文字列がフォームデータとして送信されてくる場合を考えます。(注:当然、送信前に文字列は URL エンコードされます)
フォームデータが "AAA:Id=6" というように一つだけなら、例えば先の記事の Put の場合のように送信側で data:"=AAA:Id=6" として受信側で Put(int id, [FromBody] string name) の name に文字列として取得できますが、"AAA:Id=6&AAA:Name=ガッチャマンの息子" のように 2 つ以上あると組み込みのフォーマッター・モデルバインダーではむりそうです(何故か 1 つ目の "AAA:Id=6" しか取得できません)。
と言って、先の記事の例の Post(Hero postedHero) ようにアクションメソッドの引数をコンプレックス型にはできません。何故なら、コロン ':' は C# の識別子の文字としては使えませんので、AAA:Id や AAA:Name という名前のプロパティが定義できませんから。
ではどうするかと言うと、先の記事でも紹介した MSDN Blog「How WebAPI does Parameter Binding」の記事の最初のコードにあるように HttpRequestMessage を引数に持つメソッドで取得するのがよさそうです。
具体的には以下のコードのようにします。
public async Task<List<Hero>> Post(HttpRequestMessage request)
{
HttpContent content = request.Content;
string str = await content.ReadAsStringAsync();
NameValueCollection formData =
await content.ReadAsFormDataAsync();
string str1 = formData["AAA:Id"];
string str2 = formData["AAA:Name"];
Hero postedHero =
new Hero { Id = int.Parse(str1), Name = str2 };
heroes.Add(postedHero);
return heroes;
}
そうすれば、上の画像に示したように HttpContent.ReadAsFormDataAsync メソッドでフォームデータを取得できます。
クライアント側はボディに設定する文字列を URL エンコードすること、要求ヘッダに Content-Type: application/x-www-form-urlencoded; charset=UTF-8 を含めることを忘れないようにしてください。