永続的な双方向関連付け (コールバックの関連付けとも呼ばれます) は、ワークフロー サービスが最初の呼び出し元にコールバックを送信する必要がある場合に便利です。 WCF 二重とは異なり、コールバックは将来いつでも発生する可能性があり、同じチャネルまたはチャネルの有効期間に関連付けられません。 唯一の要件は、呼び出し元に、コールバック メッセージをリッスンするアクティブなエンドポイントがあるということです。 これにより、実行時間の長い会話で 2 つのワークフロー サービスが通信できるようになります。 この記事では、永続的な双方向の相関関係の概要について説明します。
持続的二重相関の使用
永続的な二重相関を使用するには、2 つのサービスで、 NetTcpContextBinding や WSHttpContextBindingなどの双方向操作をサポートするコンテキスト対応バインディングを使用する必要があります。 呼び出し側サービスは、クライアントの ClientCallbackAddress で使用するバインドを指定して Endpoint を登録します。 受信側サービスは、最初の呼び出しでこのデータを受信し、呼び出し元のサービスにコールバックするEndpoint アクティビティ内の独自のSendで使用します。 この例では、2 つのサービスが相互に通信します。 最初のサービスは、2 番目のサービスでメソッドを呼び出し、応答を待機します。 2 番目のサービスはコールバック メソッドの名前を認識しますが、このメソッドを実装するサービスのエンドポイントはデザイン時に不明です。
注
永続的な二重は、エンドポイントの AddressingVersion が WSAddressing10 で構成されている場合にのみ使用できます。 そうでない場合は、次のメッセージで InvalidOperationException 例外がスローされます。"メッセージには、AddressingVersion のエンドポイント参照を含むコールバック コンテキスト ヘッダーが含まれています。 コールバック コンテキストは、AddressingVersion が 'WSAddressing10' で構成されている場合にのみ送信できます。
次の例では、Endpointを使用してコールバック WSHttpContextBindingを作成するワークフロー サービスがホストされています。
// Host WF Service 1.
string baseAddress1 = "http://localhost:8080/Service1";
WorkflowServiceHost host1 = new WorkflowServiceHost(GetWF1(), new Uri(baseAddress1));
// Add the callback endpoint.
WSHttpContextBinding Binding1 = new WSHttpContextBinding();
host1.AddServiceEndpoint("ICallbackItemsReady", Binding1, "ItemsReady");
// Add the service endpoint.
host1.AddServiceEndpoint("IService1", Binding1, baseAddress1);
// Open the first workflow service.
host1.Open();
Console.WriteLine("Service1 waiting at: {0}", baseAddress1);
このワークフロー サービスを実装するワークフローは、コールバックの関連付けをSend アクティビティと初期化し、Receiveと関連付けるSend アクティビティからこのコールバック エンドポイントを参照します。 次の例は、 GetWF1
メソッドから返されるワークフローを表します。
Variable<CorrelationHandle> CallbackHandle = new Variable<CorrelationHandle>();
Receive StartOrder = new Receive
{
CanCreateInstance = true,
ServiceContractName = "IService1",
OperationName = "StartOrder"
};
Send GetItems = new Send
{
CorrelationInitializers =
{
new CallbackCorrelationInitializer
{
CorrelationHandle = CallbackHandle
}
},
ServiceContractName = "IService2",
OperationName = "StartItems",
Endpoint = new Endpoint
{
AddressUri = new Uri("http://localhost:8081/Service2"),
Binding = new WSHttpContextBinding
{
ClientCallbackAddress = new Uri("http://localhost:8080/Service1/ItemsReady")
}
}
};
Receive ItemsReady = new Receive
{
ServiceContractName = "ICallbackItemsReady",
OperationName = "ItemsReady",
CorrelatesWith = CallbackHandle,
};
Activity wf = new Sequence
{
Variables =
{
CallbackHandle
},
Activities =
{
StartOrder,
new WriteLine
{
Text = "WF1 - Started"
},
GetItems,
new WriteLine
{
Text = "WF1 - Request Submitted"
},
ItemsReady,
new WriteLine
{
Text = "WF1 - Items Received"
}
}
};
2 番目のワークフロー サービスは、システム提供のコンテキスト ベースのバインドを使用してホストされます。
// Host WF Service 2.
string baseAddress2 = "http://localhost:8081/Service2";
WorkflowServiceHost host2 = new WorkflowServiceHost(GetWF2(), new Uri(baseAddress2));
// Add the service endpoint.
WSHttpContextBinding Binding2 = new WSHttpContextBinding();
host2.AddServiceEndpoint("IService2", Binding2, baseAddress2);
// Open the second workflow service.
host2.Open();
Console.WriteLine("Service2 waiting at: {0}", baseAddress2);
このワークフロー サービスを実装するワークフローは、 Receive アクティビティから始まります。 この受信アクティビティは、このサービスのコールバックの相関関係を初期化し、実行時間の長い作業をシミュレートするために一定期間遅延した後、サービスへの最初の呼び出しで渡されたコールバック コンテキストを使用して最初のサービスにコールバックします。 次の例は、 GetWF2
の呼び出しから返されるワークフローを表します。
Send アクティビティには、http://www.contoso.com
のプレースホルダー アドレスがあります。実行時に使用される実際のアドレスは、指定されたコールバック アドレスです。
Variable<CorrelationHandle> ItemsCallbackHandle = new Variable<CorrelationHandle>();
Receive StartItems = new Receive
{
CorrelationInitializers =
{
new CallbackCorrelationInitializer
{
CorrelationHandle = ItemsCallbackHandle
}
},
CanCreateInstance = true,
ServiceContractName = "IService2",
OperationName = "StartItems"
};
Send ItemsReady = new Send
{
CorrelatesWith = ItemsCallbackHandle,
Endpoint = new Endpoint
{
// The callback address on the binding is used
// instead of this placeholder address.
AddressUri = new Uri("http://www.contoso.com"),
Binding = new WSHttpContextBinding()
},
OperationName = "ItemsReady",
ServiceContractName = "ICallbackItemsReady"
};
Activity wf = new Sequence
{
Variables =
{
ItemsCallbackHandle
},
Activities =
{
StartItems,
new WriteLine
{
Text = "WF2 - Request Received"
},
new Delay
{
Duration = TimeSpan.FromMinutes(90)
},
new WriteLine
{
Text = "WF2 - Sending items"
},
ItemsReady,
new WriteLine
{
Text = "WF2 - Items sent"
}
}
};
最初のワークフローで StartOrder
メソッドが呼び出されると、次の出力が表示されます。これは、2 つのワークフローを介した実行フローを示しています。
Service1 waiting at: http://localhost:8080/Service1
Service2 waiting at: http://localhost:8081/Service2
Press enter to exit.
WF1 - Started
WF2 - Request Received
WF1 - Request Submitted
WF2 - Sending items
WF2 - Items sent
WF1 - Items Received
この例では、両方のワークフローが CallbackCorrelationInitializerを使用して相関関係を明示的に管理します。 これらのサンプル ワークフローには相関関係が 1 つしかないため、既定の CorrelationHandle 管理で十分でした。