マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

WCFASP.NET Web API で、指定の JSON を返す(送信する)方法を説明する。

JSON フォーマットとクラスの定義

JSONを返すサービスを作成する

WCFの場合

WCF で JSON を返す場合、既定では DataContractJsonSerializer? が使用される。

以下に注意する。

  • contractの定義
  • web.configの設定方法
  • urlの指定方法

DataContractJsonSerializer? を使用

  • 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>
  • "http://~/JSONService.svc/GetJson?" にリクエストを送ったときの実行結果
    {"IntKey":123,"ListKey":["List1","List2","List3"],"StringKey":"StringValue"}

JSON.NETなどを使用

  • WCF サービスを作成し、
    • コントラクト部分に WebGet? 属性を追加する(POSTの場合は、WebInvoke?属性を追加を追加する。)
    • UriTemplate? に、WebAPIに対応するURLパスの一部を設定する。
  • ポイントは以下の 2 点です。
  • サービスを実装する。
    [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>
  • "http://~/JSONService2.svc/GetJson?" にリクエストを送ったときの実行結果
    {"key":{"key1":"value1","key2":"value2","key3":"value3"}}

参考情報

WCF における JSON 処理の参考情報

注意点

  • WebサイトをIIS以下に配置した場合に例外が発生することがある。
    • 以下の例外(メッセージ)が出力されることがある。
      ASP.NET との互換性がないため、サービスをアクティブにできません。
      このアプリケーションでは、ASP.NET との互換性が有効になっています。
      web.config 内で ASP.NET の互換性モードを無効にするか、
      RequirementsMode に Allowed または Required が設定されたサービスの型に、
      AspNetCompatibilityRequirements 属性を追加してください。
  • この場合、

にあるように、サービスのクラスに、
AspNetCompatibilityRequirements? 属性を追加する。

ASP.NET Web API の場合

ASP.NET Web API は、既定で JSON.NET によって Serialize される。このため、Dictionary 型も問題なく Serialize できる。

設定

Web API の返すJSONフォーマット(JSONシリアライズのフォーマット)をWebApiConfigで、以下のように指定できる。

// JSON データにはCamelCaseを使用 (JSON.NET)
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

JSON.NETを使用

  • 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"}}

注意点

  • 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を必ずつけるようにしてください。

相互運用に関する注意事項

Java など、他プラットフォームとの相互運用を行なう際に注意すべき点。

DataContractJsonSerializer?の問題

既定の DataContractJsonSerializer では、Dictionary 型のオブジェクトを正しく扱えない。

DataContractJsonSerializer?の対策

その他のSerializerを使用する

Dictionary 型のオブジェクトを扱う場合は、JSON.NET など、その他のSerializerを使用する。

JSON フォーマットを、コントラクトとする

Java などの他プラットフォームとの相互運用を考えた場合、
いきなりPOJO または POCO をデータコントラクトとせず、
先ずは出力したい JSON フォーマットを確認する事から始める。

以下の手順で、

  1. 出力したい JSON フォーマットを決める
    (これがデータコントラクトとなる)
  2. そのフォーマットにあわせて、
    1. Java であれば POJO
    2. .NET であれば POCO

クラスを作成する。

参考

Microsoft Azure が公開している REST API

数個、Microsoft Azure が公開している REST API をピックアップした。

これらの REST API でも、JSON のフォーマットが明記されており、
JSON フォーマットレベルでデータコントラクトを結ぶ必要がある。

色々なSerializerと、その歴史

DataContractJsonSerializer?は、
WCFのデータコントラクトのSerializerとして使用されていたこともあり、

  • 前述のように、相互運用性に難があり、
  • また、匿名型などをシリアライズできない

などの問題があった。

データコントラクト不要な単方向のやり取りのために、JavaScriptSerializer?などのクラスも追加されたが、
これは、.NET3.5でサポートされなくなり、替わって、JSON.NETがデファクトになり、ASP.NET Web API の標準のシリアライザに採用された。


Tags: :.NET開発, :通信技術, :.NET Core, :ASP.NET, :ASP.NET Web API


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-07-30 (月) 16:21:45 (79d)