콜백 상관 관계라고도 하는 지속성 이중 상관 관계는 워크플로 서비스에 초기 호출자에게 콜백을 보내야 하는 요구 사항이 있는 경우에 유용합니다. WCF 이중과 달리 콜백은 나중에 언제든지 발생할 수 있으며 동일한 채널 또는 채널 수명에 연결되지 않습니다. 유일한 요구 사항은 호출자에게 콜백 메시지를 수신 대기하는 활성 엔드포인트가 있다는 것입니다. 이렇게 하면 두 워크플로 서비스가 장기간 지속되는 대화에서 통신할 수 있습니다. 이 문서에서는 지속성 이중 상관 관계에 대한 개요를 제공합니다.
지속성 이중 상관 관계 사용
지속성 이중 상관 관계를 사용하려면 두 서비스는 NetTcpContextBinding 또는 WSHttpContextBinding처럼 양방향 작업을 지원하는 컨텍스트를 활성화한 바인딩을 사용해야 합니다. 호출 서비스는 클라이언트ClientCallbackAddress에서 원하는 바인딩이 적용된 Endpoint을 등록합니다. 수신 서비스는 초기 호출에서 이 데이터를 수신한 다음 호출 서비스에 다시 호출하는 활동에서 Endpoint 자체적으로 사용합니다Send. 이 예제에서는 두 서비스가 서로 통신합니다. 첫 번째 서비스는 두 번째 서비스에서 메서드를 호출한 다음 회신을 기다립니다. 두 번째 서비스는 콜백 메서드의 이름을 알고 있지만 이 메서드를 구현하는 서비스의 엔드포인트는 디자인 타임에 알 수 없습니다.
비고
엔드포인트가 AddressingVersion이(가) WSAddressing10로 구성된 경우에만 내구성 복제 기능을 사용할 수 있습니다. 그렇지 않으면 다음 메시지와 함께 예외가 발생합니다: "메시지에는 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"
}
}
};
두 번째 워크플로 서비스는 시스템에서 제공하는 컨텍스트 기반 바인딩을 사용하여 호스팅됩니다.
// 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 메서드를 호출하면 다음 출력이 표시됩니다. 이 출력은 두 워크플로를 통한 실행 흐름을 보여 줍니다.
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상관 관계를 명시적으로 관리합니다. 이러한 샘플 워크플로에는 단일 상관 관계만 있었기 때문에 기본 CorrelationHandle 관리만으로 충분했을 것입니다.