ASP.NET Web API について、おさらい
ASP.NET MVC4 における新機能のひとつである ASP.NET Web API。
某かのリソース、POCO エンティティなどを、RESTFull に HTTP プロトコル上に公開することが、MVC3 以前と比べて容易になっている。
"APIコントローラ" の基底クラスから派生したクラスを書くわけだが、書いたメソッドがそのまま HTTP 動詞と URL にマッチする。
MVC と異なりメソッドの戻り値は ActionResult 型固定ではなく、任意の POCO エンティティを返せる。
応答の形式も、既定でも JSON と XML の両方に対応。
HTTP 要求を送る際の要求ヘッダ、Accept に "application/json" を指定するか、"application/xml" を指定するかで、JSON と XML とのいずれの形式で応答をもらうか、指定することができる。
たとえば、
public class MyPOCO
{
public string Foo { get; set; }
}
public class ValuesController : ApiController
{
public MyPOCO Get()
{
return new MyPOCO { Foo = "Bar" };
}
}
というコードを書くことで、Visual Studio 開発環境から実行して、
"http://localhost:1765/api/values"
といった URL でアクセスすれば、
といった XML 形式での応答、
Accept 要求ヘッダに "application/json" を指定すれば、
といった JSON 形式での応答が返るわけだ。
XML 形式を指定しても JSON 形式で返る!?
ただし、実際にいろいろ ASP.NET Web API 実装を書いていて気づいたことがある。
Accept 要求ヘッダに "application/xml" を指定して XML 形式による応答を期待していても、常に JSON 形式で返る場合があったのだ。
いくつか実験してわかったことなのだけど、どうやら、API コントローラのメソッドが返すオブジェクトの型に、
引数無しコンストラクタ(デフォルトコンストラクタ)が無い場合に、応答が必ず JSON 形式になるようだ。
引数無しコンストラクタがない場合
API コントローラのメソッドが返すオブジェクトの型に、引数無しコンストラクタ(デフォルトコンストラクタ) がない場合は、まず、明示的にその戻り値型に DataContract 属性を付けないと、そもそもシリアル化ができない旨の例外となる。
ということで、DataContract 属性と、必要に応じて、その戻り値型が備えるプロパティに DataMember 属性を記述してやる。
しかしそれでもなお、XML 形式で応答を返すことはできないらしい。
Accept 要求ヘッダに "application/xml" を指定しても、例外にはならないものの、JSON 形式で応答が返るのだ。
ちなみに、引数無しコンストラクタがある場合は、その引数無しコンストラクタが非 public であっても XML 形式での応答が返せるようになる。
まとめ
以上はつまるところ、.NET Framework における XML シリアル化処理の仕様・仕組みに起因しているらしい。
デフォルトコンストラクタが無く、引数付きコンストラクタしかない状況では、逆シリアル化したくても、どういった引数を与えてインスタンス生成すればよいか、機械的に判断つかないので、こういった制約があるのだろう。
昨今の状況では、JSON 形式でしか結果を返せなくても困ることはあまりないように思われるが、しかし、どうしても XML 形式と JSON 形式の双方をサポートしたい場合は、この点、注意されるのがよろしいかと思う。