WCFサービスからJSON形式でレスポンスを返す場合、List型とDictionary型を使ってデータを詰めるか、あるいはJSONに対応するプロパティを持たせたクラスを定義するなどして、戻り値の型に設定すると思います。
今回は自前で作ったJSON形式の文字列を、そのままJSONとしてレスポンスに乗せる方法を試してみました。
・JSON.NETのJArrayを使って配列データを操作する
・JSON.NETのJTokenを使ってJSONの中身を一つずつ参照しながら全項目を取得する
・【WCF】どんな型の引数でも受け取れるメソッドを作成する
・RESTなWCFサービスのクロスドメイン対応
・JSON.NETのJTokenを使ってJSONの中身を一つずつ参照しながら全項目を取得する
・【WCF】どんな型の引数でも受け取れるメソッドを作成する
・RESTなWCFサービスのクロスドメイン対応
戻り値にListとDictionaryを使った場合の問題点
Dictionaryにデータを詰めた場合、JSONに変換すると「Key」と「Value」が自動で追加されます。データを作る側の汎用性はあるんですが、JSONを受け取る側はメンバーに「Key」と「Value」がついていること前提でプログラムを組む必要があります。
※ListとDictionaryでデータを返した場合のJSONの例
{"response":[
[{"Key":"従業員コード","Value":"1001"},{"Key":"部署名","Value":"総務部"}],
[{"Key":"従業員コード","Value":"1002"},{"Key":"部署名","Value":"営業部"}],
[{"Key":"従業員コード","Value":"1003"},{"Key":"部署名","Value":"開発部"}]
]}
[{"Key":"従業員コード","Value":"1001"},{"Key":"部署名","Value":"総務部"}],
[{"Key":"従業員コード","Value":"1002"},{"Key":"部署名","Value":"営業部"}],
[{"Key":"従業員コード","Value":"1003"},{"Key":"部署名","Value":"開発部"}]
]}
これをjavascriptで読んだりすると処理が結構めんどくさいんですよね。
KeyとかValueとか使わずに、"従業員コード"で"1001"をズバッっと取得したいんです。
JSONの形式に合わせたクラスを作った場合の問題点
JSONの形式に合わせたクラスを作る場合は、当然ですがあらかじめJSONの形が決まっていないとダメです。また、JSONのフォーマットの数だけクラスも作成する必要があり、JSONの項目が可変だったりする場合に対応しきれません。
例えばこんな形式のJSONを返したい場合、
{"response":{
"従業員コード":"1001",
"部署名":"総務部"
}
}
"従業員コード":"1001",
"部署名":"総務部"
}
}
こんなクラスを用意しておく必要があります。
<DataContract()> Public Class json_response <DataMember()> Public Property 従業員コード As String <DataMember()> Public Property 部署名 As String End ClassJSONの項目が増えたら、
{"response":{
"従業員コード":"1001",
"部署名":"総務部",
"入社年度":2007
}
}
"従業員コード":"1001",
"部署名":"総務部",
"入社年度":2007
}
}
クラスのプロパティも増やす必要があります。
<DataContract()> Public Class json_response <DataMember()> Public Property 従業員コード As String <DataMember()> Public Property 部署名 As String <DataMember()> Public Property 入社年度 As Integer ''追加 End Class
これだとJSONの形が変わったらWCFサービスを毎回ビルドする必要がありますし、通信が増えればJSONに対応したクラスも増やさないといけません。
リクエストごとに戻り値の型が違う場合、WCFサービスのメソッドも増やす必要があります。
JSON形式の文字列をJSONデータとして返す
ResponseFormatにWebMessageFormat.Jsonを指定していると、文字列で作ったJSONのダブルクォーテーションにエスケープ文字「\」が追加されてしまって、JSONが崩れてしまいます。なのでResponseFormatには何も指定せず、文字列をレスポンスに直接書き込みます。
また、戻り値の型はString型ではなく、System.ServiceModel.Channels.Messageを使用しています。
例)クエリによってカラムが可変となるデータベースの検索結果を、JSON形式にシリアライズして返す
※シリアライズにはJSON.NETを使用
''IService.vb Imports System.Runtime.Serialization Imports System.ServiceModel <ServiceContract()> Public Interface IService ''ここでResponseFormatは指定しない <OperationContract(), WebInvoke(Method:="POST" _ , BodyStyle:=WebMessageBodyStyle.Wrapped _ , RequestFormat:=WebMessageFormat.Json _ , UriTemplate:="/jsonsample")> Function execSQL(ByVal sql As String) As System.ServiceModel.Channels.Message End Interface
''Service.svc.vb Imports System.Reflection Imports System.Runtime.InteropServices Public Class RestService Implements IService Function execSQL(ByVal sql As String) As System.ServiceModel.Channels.Message _ Implements IService.execSQL ''DBオープン Dim oConn As New OracleConnection oConn.ConnectionString = "User Id=XXX;Password=XXX;Data Source=XXX;" ''SQL実行 Dim oCmd As New OracleCommand oCmd.Connection = oConn oCmd.CommandText = strSqlStatement Dim oAdp As New OracleDataAdapter(oCmd) Dim ds As New DataSet oAdp.Fill(ds, "result_table") oAdp.Dispose() oCmd.Dispose() oConn.Dispose() ''JSON.NETでシリアライズ Dim jsontxt As String = JsonConvert.SerializeObject(ds, Formatting.None) ''ヘッダ追加 WebOperationContext.Current.OutgoingResponse.Headers.Add("X-Content-Type-Options", "nosniff") ''シリアライズした文字列をJSONとして返す Return WebOperationContext.Current.CreateTextResponse(jsontxt, "application/json; charset=utf-8", Encoding.UTF8) End Function End Class
実行結果の例
{"result_table":[
{"従業員コード":"1001","部署名":"総務部"},
{"従業員コード":"1002","部署名":"営業部"},
{"従業員コード":"1003","部署名":"開発部"}
]}
{"従業員コード":"1001","部署名":"総務部"},
{"従業員コード":"1002","部署名":"営業部"},
{"従業員コード":"1003","部署名":"開発部"}
]}
Dictionaryのように"Key"、"Value"が勝手に付いてこないので、受信側がJSONとして使いやすいと思います。
まとめ
DataSetからJSONへのシリアライズはJSON.NETを使用しましたが、複雑な構造のJSONを送りたい場合は自前で文字列操作してゴリゴリJSONを作らないといけないので、そこが面倒です。以上
0 件のコメント :
コメントを投稿