ASP.NET Web API で クラスを定義せずに POST された Body 値を取得する
クラスを定義することが面倒な場合、JToken や dynamic で POST の Body 値を受け取ることができる。
以下のような HTTP Request を送信し、JSON で書かれた Body 値を読み取るとする。
Content-Type : application/json Body : { "name" : "taro", "message" : "hello" }
クラスを定義する場合
Body 値をバインドするためのクラスを定義する:
public class HogeRequest { public string Name { get; set; } public string Message { get; set; } }
ApiController に以下のようにアクションを定義する:
[Route("api/model")] public void PostModel(HogeRequest request) { Debug.WriteLine(request.Name); Debug.WriteLine(request.Message); }
これで Body 値を読み取ることができるが、クラスを定義することが面倒な場合(定義したくない場合)、次のように値を取得することも可能。
JToken
アクションの引数に JToken(Newtonsoft.Json.Linq 名前空間)を定義する
[Route("api/test3")] public void PostTest3(JToken token) { Debug.WriteLine(token["name"]); Debug.WriteLine(token["message"]); dynamic request = token; Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); }
dynamic として取得することもできる。
この JToken の便利なところは、Content-Type が application/json, application/x-www-form-urlencoded の両方に対応していること。下の HTTP Request のように x-www-form-urlencoded で送信しても Body 値を取得できる。
Content-Type : application/x-www-form-urlencoded Body : name=taro&message=hello
JToken を使用する場合、NuGet から「Newtonsoft.Json」のインストールが必要(今回は version 6.0.4 を使った)。
JObject
JToken とほぼ同じで、JObject(Newtonsoft.Json.Linq 名前空間)も定義できる。
[Route("api/jobject")] public void PostTest2(JObject jObject) { Debug.WriteLine(jObject.GetValue("name")); Debug.WriteLine(jObject.GetValue("message")); dynamic request = jObject; Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); }
これも application/json, application/x-www-form-urlencoded の双方に対応。
dynamic
引数に dynamic を定義することが一番単純な場合もある。しかし、dynamic の場合は JToken, JObject と違って application/x-www-form-urlencoded では取得できないので注意。
[Route("api/dynamic")] public void PostTest(dynamic request) { Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); }
(※dynamic は application/json で送信された Body 値がバインドされる。)
FormDataCollection
最後に、application/json では取得できないが、application/x-www-form-urlencoded では取得できる FormDataCollection(System.Net.Http.Formatting 名前空間)。
[Route("api/form")] public void PostTest(FormDataCollection form) { Debug.WriteLine(form.Get("name")); Debug.WriteLine(form.Get("message")); }
(※FormDataCollection は application/x-www-form-urlencoded で送信された Body 値がバインドされる。)
System.Net.Http.Formatting.dll への参照が必要(NuGet で Microsoft.AspNet.WebApi.Client をインストール)。
最後に
JSON のみって決まっていれば dynamic、x-www-form-urlencoded と JSON 両方を受けたい場合は JToken、を利用するという感じ?
JToken も model class みたいなものですが。
と、ここまで書いていたら KeyValuePair
サンプルコード
今回検証に利用したコード。
ASP.NET Web API のバージョンは 5.2.2。
WebApiConfig.cs: using System.Web.Http; namespace WebApplication2 { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API の設定およびサービス // Web API ルート config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
SampleController:
using Newtonsoft.Json.Linq; using System.Diagnostics; using System.Net.Http.Formatting; using System.Web.Http; namespace WebApplication2.Controllers { public class HogeRequest { public string Name { get; set; } public string Message { get; set; } } public class SampleController : ApiController { [Route("api/model")] public void PostModel(HogeRequest request) { Debug.WriteLine(request.Name); Debug.WriteLine(request.Message); } [Route("api/form")] public void PostForm(FormDataCollection form) { Debug.WriteLine(form.Get("name")); Debug.WriteLine(form.Get("message")); } [Route("api/dynamic")] public void PostDynamic(dynamic request) { Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); } [Route("api/jobject")] public void PostJObject(JObject jObject) { Debug.WriteLine(jObject.GetValue("name")); Debug.WriteLine(jObject.GetValue("message")); dynamic request = jObject; Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); } [Route("api/jtoken")] public void PostJToken(JToken token) { Debug.WriteLine(token["name"]); Debug.WriteLine(token["message"]); dynamic request = token; Debug.WriteLine((string)request.name); Debug.WriteLine((string)request.message); } } }