Open棟梁Project - マイクロソフト系技術情報 Wiki
WCF や WebAPI で、指定の REST Format に適合する JSON を返す方法を説明する。
まず、どのようなフォーマットの JSON を出力したいのかを確認します。
これがなければ、始まりません。
次に、出力したい JSON に合わせて、クラスやプロパティを定義します。
基本的には、以下のルールに従って、クラスやプロパティを定義します。
出力したいJSON | 定義するクラス・プロパティ |
{ "key1" : "value1", "key2" : "value2" } | public class Sample { string key1 { get; set; } string key2 { get; set; } } |
[ "1", "2", "3" ] | List<string> listData { get; set; } |
{ "key1" : [ "1", "2", "3" ] } | public class Sample { List<string> key1 { get; set; } } |
{ "key" : { "key1" : "value1", "key2" : "value2" } } | public class Sample { string key1 { get; set; } string key2 { get; set; } } public class Sample2 { Sample key { get; set; } } |
[ { "key1" : "value1", "key2" : "value2" }, { "key1" : "value3", "key2" : "value4" } ] | public class Sample { string key1 { get; set; } string key2 { get; set; } } List<Sample> listData { get; set; } |
Visual Studio の拡張機能である、Web Essentials を使うと、JSON からクラスを自動生成してくれます。
Web Essentials は、Visual Studio のメニューから、[ツール] - [拡張機能と更新プログラム] で追加できます。
&ref(): File not found: "WebEssentials.png" at page "JSONを送受信するRESTサービスを作成する方法";
JSON 文字列をコピーし、Visual Studio のエディターで、右クリックまたは [編集] メニューから、[形式を選択して貼り付け] - [JSON をクラスとして貼り付ける] を選択すると、その JSON フォーマットに合ったクラスが生成されます。
WCF で JSON を返す場合、既定では DataContractJsonSerializer? が使用されます。
以下に注意して下さい。
[ServiceContract] public interface IJSONService { [OperationContract] [WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetJson")] Sample GetJson(); } public class JSONService : IJSONService { public Sample GetJson() { // JSON にシリアライズする元となるオブジェクトを作成する Sample sample = new Sample() { StringKey = "StringValue", IntKey = 123, ListKey = new List<string>() { "List1", "List2", "List3" } }; // クライアントにデータを返す return sample; } } public class Sample { public string StringKey { get; set; } public int IntKey { get; set; } public List<string> ListKey { get; set; } }
<system.serviceModel> <services> <service name="WebApplication1.JSONService"> <endpoint address="" binding="webHttpBinding" behaviorConfiguration="MyBehavior" contract="WebApplication1.IJSONService" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="MyBehavior"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel>
{"IntKey":123,"ListKey":["List1","List2","List3"],"StringKey":"StringValue"}
[ServiceContract] public interface IJSONService2 { [OperationContract] [WebGet(UriTemplate = "GetJson")] Message GetJson(); } public class JSONService2 : IJSONService2 { public Message GetJson() { // JSON にシリアライズする元となるオブジェクトを作成する Sample2 sample = new Sample2() { key = new Dictionary<string, string>() { {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"} } }; // JSON.NET を使用して JSON 形式にシリアライズ string jsonStr = JsonConvert.SerializeObject(sample); // 'X-Content-Type-Options: nosniff' ヘッダーを追加する WebOperationContext.Current.OutgoingResponse.Headers.Add("X-Content-Type-Options", "nosniff"); // JSON を返す return WebOperationContext.Current.CreateTextResponse(jsonStr, "application/json; charset=utf-8", Encoding.UTF8); } } public class Sample2 { public Dictionary<string, string> key { get; set; } }
<system.serviceModel> <services> <service name="WebApplication1.JSONService2"> <endpoint address="" binding="webHttpBinding" behaviorConfiguration="MyBehavior" contract="WebApplication1.IJSONService2" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="MyBehavior"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel>
{"key":{"key1":"value1","key2":"value2","key3":"value3"}}
WCF における REST(JSON) 処理の参考情報
ASP.NET との互換性がないため、サービスをアクティブにできません。 このアプリケーションでは、ASP.NET との互換性が有効になっています。 web.config 内で ASP.NET の互換性モードを無効にするか、 RequirementsMode に Allowed または Required が設定されたサービスの型に、 AspNetCompatibilityRequirements 属性を追加してください。
この場合、
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class CalculatorService : ICalculatorSession
にあるように、サービスのクラスに、
AspNetCompatibilityRequirements? 属性を追加する。
ASP.NET Web API は、既定で JSON.NET によって Serialize されます。
このため、Dictionary 型も問題なく Serialize できます。
public class ValuesController : ApiController { // GET api/values public Sample Get() { // JSON にシリアライズする元となるオブジェクトを作成する Sample sample = new Sample() { key = new Dictionary<string, string>() { {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"} } }; // JSON を返す return sample; } } public class Sample { public Dictionary<string, string> key { get; set; } }
{"key":{"key1":"value1","key2":"value2","key3":"value3"}}
Java などの他プラットフォームとの相互運用を考えた場合も、まずは出力したい JSON フォーマットを確認することが基本です。
つまり、以下のような流れとなります。
クラスを作成する。
.NET と Java では、JSON シリアライザの挙動が違います。
言語 | POJO / POCO サンプル | シリアライズされた JSON |
Java | public class Sample { public String _key1; public String _key2; public void setKey1(String key1) { this._key1 = key1; } public String getKey1() { return this._key1; } public void setKey2(String key2) { this._key2 = key2; } public String getKey2() { return this._key2; } } | { "key1" : "value1", "key2" : "value2" } |
public class Sample { public HashMap?<String, String> _key; public void setKey(HashMap?<String, String> key) { this._key = key; } public void getKey() { return this._key; } } | ||
.NET | public class Sample { public string key1 { get; set; } public string key2 { get; set; } } | |
public class Sample { public Dictionary<string, string> key { get; set; } } | [ { "Key": "Prop1", "Value": "Value1" }, { "Key": "Prop2", "Value": "Value2" } ] 同じ形式のジェネリック型であっても、 Java と .NET ではシリアライズ結果が異なる |
数個、Microsoft Azure が公開している REST API をピックアップしてみました。
resourceGroup の name が REST の Uri に含まれていて、Responce が JSON 形式で返されます
Responce が HTTP 200 だけのもあります
呼び出すパラメタが大きく、変更を加える操作は、PUT で行われ、Request Body に パラメタが JSON 形式で渡されます。
これらの REST API でも、JSON のフォーマットが明記されています。
このことからも、JSON フォーマットレベルでデータコントラクトを結ぶ必要があると思います。