トップ回答者
サービス操作中にコールバックする方法

質問
-
#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ライブラリも品質が良くないし。(例の欠如が致命的)
回答
-
コールバック実装クラスにCallabckBehaviroAttributeを付して
クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。
# 私は下記のサイトを見て、このCallbackBehaviorを知りました。
# http://handcraft.blogsite.org/ComponentGeek/ShowArticle/29.aspx
また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
サービス操作を呼び出している場合、CallbackBehaviorAttributeの
UseSynchronizationContextにfalseを指定しないと
コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
デッドロックするというのも問題になるかもです。
# ConcurrensyModeだけで足りるのか、両方要るのかは確認してません。
すべての返信
-
#自己レス
どうもメッセージが完結(メソッド呼び出しから派生したプロシージャからReturnするまで)する前にサービス操作をおこなうと
待ちになりタイムアウトするようです。
今回の具体例としては、
クライアントが「他メンバー参加」コールバックを受信し、そのプロシージャで「最新メンバーリスト取得」サービス要求をおこなう
という場合です。
最初のコールバックがWCFメッセージとして完結する前にサービス要求という新しいWCFメッセージを起こしているのが原因のようです。
ほんとにだめなのかと思いつつもやり方やパラメータが見つからないため、とりあえずの解決策。
・コールバック専用のサービスを作成。>Portを2つ使う羽目に。
・サービス操作メソッドでコールバックをおこなう場合(新たなメッセージを起こす場合)は、必ずOperationCompletedイベントにておこなう。>メッセージの完結
こんなところです。
-
遅い返信かつためしていないのでお役にたてるかわかりませんが、
メソッドを呼び出しているクライアントのコールバックを呼び出す場合は
ServiceBahaviorのConcurrenyModeをReentrantにすればよいのではないでしょうか?
[ServiceBahavior(ConcurrencyMode = CucurrencyMode.Reentrant)]
class ServiceImpl : IService
{
....
}
そうしないとクライアント側のサービスを呼び出しているスレッドから
ブロックされてTimeoutになった記憶があります。
-
返信ありがとうございます。
要は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イベントでもだめなのでなおさらそう言えます。
結局解決策が見つからず前投稿となりました。 -
コールバック実装クラスにCallabckBehaviroAttributeを付して
クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。
# 私は下記のサイトを見て、このCallbackBehaviorを知りました。
# http://handcraft.blogsite.org/ComponentGeek/ShowArticle/29.aspx
また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
サービス操作を呼び出している場合、CallbackBehaviorAttributeの
UseSynchronizationContextにfalseを指定しないと
コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
デッドロックするというのも問題になるかもです。
# ConcurrensyModeだけで足りるのか、両方要るのかは確認してません。 -
miromok さんからの引用 クライアント側のConcurrencyModeにReentrantを指定するのはどうでしょう。
これについては、Singleにしています。
クライアント側でConcurrencyをあまり意識してなかったので、試してみて問題ないか確認してみます。
時系列的なクライアントイベントも要求としてあるので、そこらへんが気になるところです。
miromok さんからの引用 また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
サービス操作を呼び出している場合、CallbackBehaviorAttributeの
UseSynchronizationContextにfalseを指定しないと
コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
デッドロックするというのも問題になるかもです。たぶん挙動的にはこれです。
サービスメソッドのEndSubに到達しませんから。
1年経ちプロジェクトとしてはほぼ完成形ですので、すぐにとはいきませんが
具体的な方法をお教えいただきましたので、後日時間を見て試してみます。
-
mkmr さんからの引用
また、クライアント側がWindowsフォームアプリケーションのUIスレッドから
サービス操作を呼び出している場合、CallbackBehaviorAttributeの
UseSynchronizationContextにfalseを指定しないと
コールバック呼び出しがUIスレッドのサービス操作呼び出しの完了を待ってしまい
デッドロックするというのも問題になるかもです。上記の対応にて、動作しました。
Concurrencyのあたりで今までとの比較で基本動作に問題が起きないか様子見しているところです。
助かりました。
ありがとうございました。