私は既存のアプリケーションにWCFを実装しています。実装の一環として、別のサービス(LegacyAppと呼ぶ)を呼び出してインスタンス化するManagerというシングルトンサービスを作成しました。 LegacyAppはセッション単位のサービスであり、モノリシックオブジェクトとしてインスタンス化された既存のアプリケーション以上のものではありません(この設計は既存のアプリケーションのアーキテクチャによるものです)。アプリケーション間でWCFでInstanceContextSharingを実装するにはどうすればよいですか?
任意のクライアント(.NET、Javaなど)がManagerサービスに接続し、既存のLegacyAppインスタンスのリストを取得し、既存のインスタンスに接続するか、新しいインスタンスを取得できるという考えがあります。
MSDN examplesごとにInstanceContextSharingを実装しましたが、これはアプリケーション単位でしか動作しません。つまり、Managerサービスで複数のLegacyAppクライアントを作成した場合、Managerサービスは異なるLegacyAppコンテキスト間を切り替えることができます固有のセッションIDを持つカスタムヘッダーただし、同じユニークなセッションIDを持つ新しいクライアントを使用してLegacyAppに接続しようとすると、他のクライアントが接続されていないかのようにLegacyAppサービスが動作します。
私の質問は次のとおりです。異なるアプリケーション間で動作するWCFでセッション共有を実装するにはどうすればよいですか?
編集(1) ManagerサービスとLegacyAppサービスが同じサービスホストでホストされています。マネージャサービスは、プロキシクライアント(別のプロキシライブラリで定義されています)を使用してLegacyAppサービスに接続します。ある意味では、サービスホストは、クライアントとサーバーの両方が同じサービスホストにあるため、それ自体のクライアントです。この同じプロキシライブラリを使用してプロキシクライアントを作成する別のクライアント(WinFormsクライアント)を作成すると、上記の動作が発生します。
以下は、私が実装したコードの抜粋です。拡張クラスとShareable属性クラスは、MSDNの例と同じです。簡潔にするために、私は様々なサービスとクライアントの無関係な部分を除外しました。
LegacyAppサービス:
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)>
<Shareable()>
Public Class LegacyAppService
Implements ILegacyApp
Private _foo As String = "Not Set"
Public Sub SetFoo(ByVal foo As String) Implements ILegacyApp.SetFoo
_foo = foo
End Sub
Public Function GetFoo() As String Implements ILegacyApp.GetFoo
Return _foo
End Function
End Class
LegacyAppクライアント:
Public Class LegacyAppClient
Inherits ClientBase(Of ILegacyApp)
Implements ILegacyApp
Public Sub New()
Me.New(String.Empty)
End Sub
Public Sub New(ByVal id As String)
If IsNothing(id) OrElse id = String.Empty Then
_uniqueID = NewInstanceId()
Else
_uniqueID = id
End If
CreateContextHeader()
End Sub
Private Shared Function NewInstanceId() As String
Dim random As Byte() = New Byte(CInt(256/8 - 1)) {}
RandomNumberGenerator.GetBytes(random)
Return Convert.ToBase64String(random)
End Function
Private Sub CreateContextHeader()
_contextHeader = MessageHeader.CreateHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace, _uniqueID)
End Sub
Public ReadOnly Property ID() As String
Get
Return _uniqueID
End Get
End Property
Public Sub SetFoo(ByVal foo As String) Implements ILegacyApp.SetFoo
Using New OperationContextScope(InnerChannel)
OperationContext.Current.OutgoingMessageHeaders.Add(_contextHeader)
Channel.SetFoo(foo)
End Using
End Sub
Public Function GetFoo() As String Implements ILegacyApp.GetFoo
Using New OperationContextScope(InnerChannel)
OperationContext.Current.OutgoingMessageHeaders.Add(_contextHeader)
Return Channel.GetFoo()
End Using
End Function
End Class
Managerサービス:
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single)>
Public Class ManagerService
Implements IManager
Public Function CreateService() As String Implements IManager.CreateService
Dim openError As Integer
Dim legacyAppClient As New LegacyAppClient
legacyAppClient.SetFoo(legacyAppService.ID)
Return legacyAppClient.ID
End Function
End Class
テストクライアント:
<...>
Dim sessionID As String
Dim legacyApp As LegacyAppClient
sessionID = _managerClient.CreateService()
legacyAppClient = New LegacyAppClient(sessionID)
Dim foo As String = legacyAppClient.GetFoo()
<...>
foo
を照会するときにsessionID
の値を返すことが予想されますが、テストクライアントで呼び出されたlegacyAppClient.GetFoo()
メソッドが「未設定」を返しています。
編集(2) 私はこの問題について誤って考えていますか?テストクライアントからのすべての呼び出しをManagerサービスに送り、それをLegacyAppサービスへのラッパーとして機能させる必要がありますか?
それはどのように明確ではありません「コールと(私たちはLegacyAppを呼ぶことにします)別のサービスがインスタンス化」実施されます。レガシーアプリケーションが、マネージャがプロキシを介して呼び出す別のWCFサービスであるとお考えですか? –
十分な詳細を提示しなかったことを謝罪します。元の質問を編集して、問題のコードの簡単な概要を含めました。どのようにこの作品を理解しようとあなたの助けに感謝! – dthagard