【WCF】リクエストに何でも受け取るメソッドを作成する


WCFを使って社内サービスを作成していますが、ユーザーが様々なフォーマットでデータを送ってくるので困っています。
引数に渡されるデータのフォーマットをあらかじめクラス定義しておけば良いのですが、渡ってくる可能性のあるフォーマットを事前にすべて把握しておく必要があるので、膨大な作業となってしまいます。

クライアントからどんな形式のデータが来るか分からない場合に、サービス側でデータを判断してリクエストの振り分けが出来ないか、考えてみました。



WCFサービスのメソッドの引数をObject型にしてみる

単純に引数の型をObject型にしてみましたが、リクエスト受信に例外が発生してしまいました。
IISのログは出力されていましたが、WCFサービスのメソッド内のログ出力は動いていなかったので、メソッドの入り口で落ちたようです。
<OperationContract(),
WebInvoke(Method:="POST" _
          , BodyStyle:=WebMessageBodyStyle.Wrapped _
          , RequestFormat:=WebMessageFormat.Json _
          , UriTemplate:="/test")>
Function PostMethod(ByVal obj As Object) As System.ServiceModel.Channels.Message
サービスが引数をシリアライズする際に、Object型の中身の型を判断できないみたいです。
引数ありのメソッドの汎用化は無理っぽいですね。

引数なしのメソッドにしてみる

引数のシリアライズで落ちるので、引数なしのメソッドにしてみました。
<OperationContract(),
WebInvoke(Method:="POST" _
          , BodyStyle:=WebMessageBodyStyle.Wrapped _
          , RequestFormat:=WebMessageFormat.Json _
          , UriTemplate:="/test")>
Function PostMethod() As System.ServiceModel.Channels.Message
こうすると、任意の引数で呼び出されても、通信はうまく通るようです。
その代わりクライアントからどんなデータが送られて来ているのかは、リクエストの中身を直接見ないといけません。

リクエストメッセージの中身を直接見る

例として、クライアントからは以下のような2種類の異なるJSONデータが送られてくるとします。
【例1】
{
    "ログインパラメータ" : {
        "ユーザー名": "テストユーザー",
        "パスワード": "12345678",
        "ログイン日時": "20170101"
    }
}

【例2】
{
    "プロジェクト名": "2018年システム更新",
    "担当システム": "WEB",
    "グループ": [{
        "リーダー": "斉藤",
        "サブリーダー": "田中",
        "メンバー": "山下"
        },{
        "リーダー": "佐藤",
        "サブリーダー": "安部",
        "メンバー": "渡辺"
    }]
}


サービス側ではSystem.ServiceModel.Channels.Messageを使用して、メッセージの生データを取得します。
Dim msg As System.ServiceModel.Channels.Message
msg = OperationContext.Current.RequestContext.RequestMessage
Console.WriteLine(msg.ToString)

結果

【例1】
<root type="object">
  <a:item xmlns:a="item" item="ログインパラメータ" type="object">
    <a:item xmlns:a="item" item="ユーザー名" type="string">テストユーザー</a:item>
    <a:item xmlns:a="item" item="パスワード" type="string">12345678</a:item>
    <a:item xmlns:a="item" item="ログイン日時" type="string">20170101</a:item>
  </a:item>
</root>

【例2】
<root type="object">
  <a:item xmlns:a="item" item="プロジェクト名" type="string">2018年システム更新</a:item>
  <a:item xmlns:a="item" item="担当システム" type="string">WEB</a:item>
  <a:item xmlns:a="item" item="グループ" type="array">
    <item type="object">
      <a:item xmlns:a="item" item="リーダー" type="string">斉藤</a:item>
      <a:item xmlns:a="item" item="サブリーダー" type="string">田中</a:item>
      <a:item xmlns:a="item" item="メンバー" type="string">山下</a:item>
    </item>
    <item type="object">
      <a:item xmlns:a="item" item="リーダー" type="string">佐藤</a:item>
      <a:item xmlns:a="item" item="サブリーダー" type="string">安部</a:item>
      <a:item xmlns:a="item" item="メンバー" type="string">渡辺</a:item>
    </item>
  </a:item>
</root>

リクエストメッセージの中身はXML形式となっているようです。
後はデータの内容を判断して処理を振り分けることが出来れば、1つのメソッドで異なる型の引数の呼び出しに対応出来そう。

まとめ

データのフォーマットの定義は結局どこかに持っておくことになりますが、フォーマットの形式を外部ファイルやデータベースに外出しすることで、メソッドは汎用的なものが作れそうです。
ちょっと無理やりな感じになりましたが、もっと良いやり方が見つかるまでこの方法を採用したいと思います。

以上

<スポンサーリンク>


0 件のコメント :

コメントを投稿