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 Class
JSONの項目が増えたら、{"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 件のコメント :
コメントを投稿