none
サービス操作中にコールバックする方法 RRS feed

  • 質問

  • #VB.NET

     

    【WCF構成】

    Windowsサービスホスト、NetTcpBinding、PerSession

     

    【おこないたいこと】

    要求/応答操作のサービス側実装内にてコールバック(OneWay)をおこないたい。

     

    【サービス側サンプル】

        ' IsInitiating=True

        Public Function Connect() As Integer Implements IService.Connect

            Try
                ' コールバックチャネルの取得
                Dim oc As OperationContext = OperationContext.Current
                Dim callback As IServiceCallback = oc.GetCallbackChannel(Of IServiceCallback)()

     

                Dim callbackresult As IAsyncResult = callback.BeginAsynchronousCallback(Nothing, Nothing)
                callback.EndAsynchronousCallback(callbackresult) ' これはあっても無くても一緒

     

                Return _SessionID

     

            Catch ex As Exception

            End Try

        End Function

    【問題】

    ConnectメソッドがTimeOut。

    クライアント側のメッセージは、TimeOut後、

    AsynchronousCallbackハンドラ内MessageBox、TimeOut例外ダイアログの順に同時表示される。

    AsyncPattern=False,IsOneWay=Trueなコールバックでも同様。

    #コールバックは結果的にされるので何かが阻害していることはわかる。

    #チャネルとかそこらへんの知識が欠落してるんだろうか?

     

    【その他】

    Connectメソッド内でOperationContext.OperationCompletedをハンドルして、つまりメソッド完了時にコールバックするとOK。

     

    【質問】

    場面的にはそう無いでしょうが、あるなら他クライアント(他Session)への一斉通知とかでしょうか。

    「その他」で書いた方法(考え的にはこっちのほうがまともかも)があるので困ることもなさそうですが

    出来るのならその方法、そしてサンプルの何が間違っているのかということを知りたいと思っています。

    お分かりの方がいらっしゃいましたらお願いいたします。

     

    また、WCFに関する有用な情報ポインタがあればおすそ分けしていただけたらと思います。

    #セミナーとかもほとんど無いねぇ。。。

    #MSDNライブラリも品質が良くないし。(例の欠如が致命的)

    2007年8月22日 2:21

回答

  • コールバック実装クラスにCallabckBehaviroAttributeを付して

    クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。

    # 私は下記のサイトを見て、このCallbackBehaviorを知りました。

    # http://handcraft.blogsite.org/ComponentGeek/ShowArticle/29.aspx


    また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
    サービス操作を呼び出している場合、CallbackBehaviorAttributeの
    UseSynchronizationContextにfalseを指定しないと
    コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
    デッドロックするというのも問題になるかもです。
    # ConcurrensyModeだけで足りるのか、両方要るのかは確認してません。

    2008年7月6日 15:28

すべての返信

  • #自己レス

     

    どうもメッセージが完結(メソッド呼び出しから派生したプロシージャからReturnするまで)する前にサービス操作をおこなうと

    待ちになりタイムアウトするようです。

    今回の具体例としては、

    クライアントが「他メンバー参加」コールバックを受信し、そのプロシージャで「最新メンバーリスト取得」サービス要求をおこなう

    という場合です。

    最初のコールバックがWCFメッセージとして完結する前にサービス要求という新しいWCFメッセージを起こしているのが原因のようです。

     

    ほんとにだめなのかと思いつつもやり方やパラメータが見つからないため、とりあえずの解決策。

     

    ・コールバック専用のサービスを作成。>Portを2つ使う羽目に。

    ・サービス操作メソッドでコールバックをおこなう場合(新たなメッセージを起こす場合)は、必ずOperationCompletedイベントにておこなう。>メッセージの完結

     

    こんなところです。

    2007年9月5日 1:45
  • 遅い返信かつためしていないのでお役にたてるかわかりませんが、

    メソッドを呼び出しているクライアントのコールバックを呼び出す場合は

    ServiceBahaviorのConcurrenyModeをReentrantにすればよいのではないでしょうか?

    [ServiceBahavior(ConcurrencyMode = CucurrencyMode.Reentrant)]

    class ServiceImpl : IService

    {

      ....

    }

    そうしないとクライアント側のサービスを呼び出しているスレッドから

    ブロックされてTimeoutになった記憶があります。

     

    2007年12月3日 12:38
  • 返信ありがとうございます。

     

    要はService.Login() As Boolean の中でReturnの直前にLoggedInイベント(コールバック)を呼び出したいわけです。

    なのでサービスインスタンス側のConcurrencyModeはあまり関係ないような気がします。

    実際今も再チャレンジしましたがだめでした。OperationCompletedイベントへの実装も含めて。

     

    挙動としては

    Public Class TestService

        Public Function Login() As Boolean

            _MyCallbackChannel.TestCallback()

            Hoge()

            Return True

        End Function

    End Class

    Hoge() というか関数としてはReturnまで実行されています。

    つまり、メッセージングのレベル(関数の戻りとコールバックの送信)でかち合っているようです。

    で、OperationContext.OperationCompletedイベントでもだめなのでなおさらそう言えます。

    結局解決策が見つからず前投稿となりました。
    2007年12月4日 0:46
  • ↑なんか前投稿と例が違いましたが結果は同じです。

    2007年12月4日 0:48
  • コールバック実装クラスにCallabckBehaviroAttributeを付して

    クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。

    # 私は下記のサイトを見て、このCallbackBehaviorを知りました。

    # http://handcraft.blogsite.org/ComponentGeek/ShowArticle/29.aspx


    また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
    サービス操作を呼び出している場合、CallbackBehaviorAttributeの
    UseSynchronizationContextにfalseを指定しないと
    コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
    デッドロックするというのも問題になるかもです。
    # ConcurrensyModeだけで足りるのか、両方要るのかは確認してません。

    2008年7月6日 15:28
  •  miromok さんからの引用

    クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。

     

    これについては、Singleにしています。

    クライアント側でConcurrencyをあまり意識してなかったので、試してみて問題ないか確認してみます。

    時系列的なクライアントイベントも要求としてあるので、そこらへんが気になるところです。

     miromok さんからの引用

    また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
    サービス操作を呼び出している場合、CallbackBehaviorAttributeの
    UseSynchronizationContextにfalseを指定しないと
    コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
    デッドロックするというのも問題になるかもです。

     

    たぶん挙動的にはこれです。

    サービスメソッドのEndSubに到達しませんから。

     

    1年経ちプロジェクトとしてはほぼ完成形ですので、すぐにとはいきませんが

    具体的な方法をお教えいただきましたので、後日時間を見て試してみます。

    2008年7月7日 2:55
  •  mkmr さんからの引用

    また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
    サービス操作を呼び出している場合、CallbackBehaviorAttributeの
    UseSynchronizationContextにfalseを指定しないと
    コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
    デッドロックするというのも問題になるかもです。

     

    上記の対応にて、動作しました。

    Concurrencyのあたりで今までとの比較で基本動作に問題が起きないか様子見しているところです。

    助かりました。

    ありがとうございました。
    2008年7月23日 7:50