「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>JSON]] * 目次 [#ec67115c] #contents *概要 [#zb9de49d] [[WCF]] や [[ASP.NET Web API]] で、指定の JSON を返す方法を説明する。 *JSON フォーマットとクラスの定義 [#k6b79e72] [[コチラ>JSONのparseを色々試してみた。#vf3529ba]]を参照。 *JSONを返すサービスを作成する [#n81c4388] **[[WCF]]の場合 [#wdb092a0] [[WCF]] で JSON を返す場合、既定では DataContractJsonSerializer が使用される。 以下に注意する。 -contractの定義 -web.configの設定方法 -urlの指定方法 ***DataContractJsonSerializer を使用 [#c008c778] -[[WCF]] サービスを作成し、 --コントラクト部分に WebGet 属性を追加する(POSTの場合は、WebInvoke属性を追加を追加する。) --UriTemplate に、WebAPIに対応するURLパスの一部を設定する。 -ポイントは以下の 2 点。 --ResponseFormat に、WebMessageFormat.Json を指定し、JSON を返すことを宣言する。 --サービスメソッドの戻り値の型に、先ほど定義したクラス / プロパティの型を指定する。 -サービスを実装する。 [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; } } -作成した [[WCF]] サービスを、[[REST]] サービスとして公開するための設定を web.config に行う。 <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> -&color(red){"http://~/JSONService.svc/GetJson"}; にリクエストを送ったときの実行結果 {"IntKey":123,"ListKey":["List1","List2","List3"],"StringKey":"StringValue"} ***JSON.NETなどを使用 [#t49e9049] -[[WCF]] サービスを作成し、 --コントラクト部分に WebGet 属性を追加する(POSTの場合は、WebInvoke属性を追加を追加する。) --UriTemplate に、WebAPIに対応するURLパスの一部を設定する。 -ポイントは以下の 2 点です。 --ResponseFormat には何も指定しない --サービスメソッドの戻り値の型は、[[System.ServiceModel.Channels.Message>https://msdn.microsoft.com/ja-jp/library/system.servicemodel.channels.message.aspx]] を指定する~ ([[WCF]] の Message Body に JSON を直接書き込む) -サービスを実装する。 [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; } } -作成した [[WCF]] サービスを、[[REST]] サービスとして公開するための設定を web.config に行う。 <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> -&color(red){"http://~/JSONService2.svc/GetJson"}; にリクエストを送ったときの実行結果 {"key":{"key1":"value1","key2":"value2","key3":"value3"}} ***参考情報 [#g54ac3a7] [[WCF]] における JSON 処理の参考情報 -WCF を利用した RESTful Web サービス の 作成~ http://garafu.blogspot.jp/2013/08/wcf-restful-web.html -WCF Web サービス に JSON オブジェクト を 渡す 方法~ http://garafu.blogspot.jp/2014/05/wcf-request-jsonobject.html -How to create a JSON WCF RESTful Service in 60 seconds - CodeProject~ http://www.codeproject.com/Articles/167159/How-to-create-a-JSON-WCF-RESTful-Service-in-sec -[[WCF における REST(JSON)のサンプル・コード>https://github.com/OpenTouryoProject/OpenTouryotemplates/tree/develop/root_VS2012/programs/C%23/Samples/WebApp_sample/ProjectX_sample/App_Code]] ***注意点 [#u6f987f4] -DataContractJsonSerializerを使用する場合、[[相互運用性に注意>#nf281504]]する。 -WebサイトをIIS以下に配置した場合に例外が発生することがある。 --以下の例外(メッセージ)が出力されることがある。 ASP.NET との互換性がないため、サービスをアクティブにできません。 このアプリケーションでは、ASP.NET との互換性が有効になっています。 web.config 内で ASP.NET の互換性モードを無効にするか、 RequirementsMode に Allowed または Required が設定されたサービスの型に、 AspNetCompatibilityRequirements 属性を追加してください。 --この場合、 ---ASP.NET 互換性~ https://msdn.microsoft.com/ja-jp/library/ms752234.aspx~ [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class CalculatorService : ICalculatorSession >にあるように、サービスのクラスに、~ AspNetCompatibilityRequirements 属性を追加する。 **[[ASP.NET Web API]] の場合 [#paf23e5b] [[ASP.NET Web API]] は、既定で JSON.NET によって Serialize される。このため、[[Dictionary 型も問題なく Serialize できる。>#nf281504]] ***設定 [#sbdd2b91] Web API の返すJSONフォーマット(JSONシリアライズのフォーマット)を[[WebApiConfig>ASP.NET Web API#z826dd05]]で、以下のように指定できる。 // JSON データにはCamelCaseを使用 (JSON.NET) config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); ***JSON.NETを使用 [#lf9e738a] - Web アプリケーションに、Web API を作成する。 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; } } - "http://~/api/Values" にリクエストを送ったときの実行結果 {"key":{"key1":"value1","key2":"value2","key3":"value3"}} ***注意点 [#t8399537] -[[ASP.NET Web API]] の注意点~ 既定では、[[ASP.NET Web API]] は、HTTP リクエストに含まれる Accept ヘッダーの内容により、クライアントに返すデータの形式が決められます。 --Acceptに''application/xml''が含まれていた場合は、XML として返されます。(レスポンスのContent-Typeヘッダーが''application/xml''となる) --Acceptに''application/json''が含まれていた場合は、JSON として返されます。(レスポンスのContent-Typeヘッダーが''application/json''となる)~ このため、常に JSON としてデータを受け取りたい場合は、リクエストヘッダーに''Accept: application/json''を必ずつけるようにしてください。 *JSONを受信するサービスを作成する [#fb585173] **[[WCF]] の場合 [#e09891e6] **[[ASP.NET Web API]] の場合 [#s4811ff5] *相互運用に関する注意事項 [#nf281504] Java など、他プラットフォームとの相互運用を行なう際に注意すべき点。 **DataContractJsonSerializerの問題 [#neffc7c2] [[既定の DataContractJsonSerializer では、Dictionary 型のオブジェクトを正しく扱えない。>JSONのparseを色々試してみた。#w5b8ea38]] **DataContractJsonSerializerの対策 [#bd99e595] ***その他のSerializerを使用する [#da12b7ef] Dictionary 型のオブジェクトを扱う場合は、[http://www.newtonsoft.com/json JSON.NET] など、その他のSerializerを使用する。 ***JSON フォーマットを、コントラクトとする [#y40ce141] Java などの他プラットフォームとの相互運用を考えた場合、~ いきなりPOJO または POCO をデータコントラクトとせず、~ 先ずは出力したい JSON フォーマットを確認する事から始める。 以下の手順で、 +出力したい JSON フォーマットを決める~ (これがデータコントラクトとなる) +そのフォーマットにあわせて、 ++Java であれば POJO ++.NET であれば POCO [[クラスを作成する。>JSONのparseを色々試してみた。#vf3529ba]] *参考 [#p44820ed] -[[JSONのparseを色々試してみた。]] **Microsoft Azure が公開している [[REST]] API [#lcad8d73] 数個、Microsoft Azure が公開している [[REST]] API をピックアップした。 -List all virtual machines in a resource group~ https://msdn.microsoft.com/en-us/library/azure/mt163572.aspx >resourceGroup の name が REST の Uri に含まれていて、Responce が JSON 形式で返されます -Start a virtual machine~ https://msdn.microsoft.com/en-us/library/azure/mt163628.aspx >Responce が HTTP 200 だけのもあります -Create or update a virtual machine~ https://msdn.microsoft.com/en-us/library/azure/mt163591.aspx >呼び出すパラメタが大きく、変更を加える操作は、PUT で行われ、Request Body に パラメタが JSON 形式で渡されます。 これらの [[REST]] API でも、JSON のフォーマットが明記されており、~ JSON フォーマットレベルでデータコントラクトを結ぶ必要がある。 **色々なSerializerと、その歴史 [#ma60357f] DataContractJsonSerializerは、~ [[WCF]]のデータコントラクトのSerializerとして使用されていたこともあり、 -前述のように、相互運用性に難があり、 -また、匿名型などをシリアライズできない などの問題があった。 データコントラクト不要な単方向のやり取りのために、JavaScriptSerializerなどのクラスも追加されたが、~ これは、.NET3.5でサポートされなくなり、替わって、JSON.NETがデファクトになり、[[ASP.NET Web API]] の標準のシリアライザに採用された。 -.NET3.5ではオブジェクトのJSONシリアライズが面倒くさい! : @jsakamoto~ http://devadjust.exblog.jp/7474060/ -.NETのJSONシリアライザの速度比較 - Qiita~ http://qiita.com/t_takahari/items/6855dfe78071bb5eaef6 -c# - What's the difference between DataContractJsonSerializer and JavaScriptSerializer? - Stack Overflow~ http://stackoverflow.com/questions/9301878/whats-the-difference-between-datacontractjsonserializer-and-javascriptserialize ---- Tags: [[:.NET開発]], [[:.NET Core]], [[:ASP.NET]], [[:ASP.NET Web API]]