Partilhar via


Correlação duplex durável

A correlação duplex durável, também conhecida como correlação de retorno de chamada, é útil quando um serviço de fluxo de trabalho tem um requisito para enviar um retorno de chamada para o chamador inicial. Ao contrário do duplex WCF, o retorno de chamada pode acontecer a qualquer momento no futuro e não está vinculado ao mesmo canal ou ao tempo de vida do canal. O único requisito é que o chamador tenha um ponto de extremidade ativo escutando a mensagem de retorno de chamada. Isso permite que dois serviços de fluxo de trabalho se comuniquem em uma conversa de longa duração. Este artigo fornece uma visão geral da correlação duplex durável.

Usando correlação duplex durável

Para usar a correlação duplex durável, os dois serviços devem usar uma associação habilitada para contexto que ofereça suporte a operações bidirecionais, como NetTcpContextBinding ou WSHttpContextBinding. O serviço de chamada registra um ClientCallbackAddress com a vinculação desejada em seu cliente Endpoint. O serviço recetor recebe esses dados na chamada inicial e, em seguida, usa-os por conta própria Endpoint na Send atividade que faz a chamada de volta para o serviço de chamada. Neste exemplo, dois serviços se comunicam entre si. O primeiro serviço invoca um método no segundo serviço e, em seguida, aguarda uma resposta. O segundo serviço sabe o nome do método de retorno de chamada, mas o ponto de extremidade do serviço que implementa esse método não é conhecido em tempo de design.

Nota

O duplex durável só pode ser usado quando o AddressingVersion do ponto de extremidade está configurado com WSAddressing10. Se não for, uma InvalidOperationException exceção será lançada com a seguinte mensagem: "A mensagem contém um cabeçalho de contexto de retorno de chamada com uma referência de ponto de extremidade para AddressingVersion. O contexto de retorno de chamada só pode ser transmitido quando a AddressingVersion está configurada com 'WSAddressing10'."

No exemplo a seguir, é hospedado um serviço de fluxo de trabalho que cria um retorno Endpoint de chamada usando WSHttpContextBindingo .

// 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);

O fluxo de trabalho que implementa esse serviço de fluxo de trabalho inicializa a correlação de retorno de chamada com sua Send atividade e faz referência a esse ponto de extremidade de retorno de chamada a Receive partir da atividade que se correlaciona com o Send. O exemplo a seguir representa o fluxo de trabalho que é retornado do GetWF1 método.

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"
        }
     }
};

O segundo serviço de fluxo de trabalho é hospedado usando uma associação baseada em contexto fornecida pelo sistema.

// 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);

O fluxo de trabalho que implementa esse serviço de fluxo de trabalho começa com uma Receive atividade. Essa atividade de recebimento inicializa a correlação de retorno de chamada para este serviço, atrasa por um período de tempo para simular o trabalho de longa duração e, em seguida, chama de volta para o primeiro serviço usando o contexto de retorno de chamada que foi passado na primeira chamada para o serviço. O exemplo a seguir representa o fluxo de trabalho retornado de uma chamada para GetWF2. A Send atividade tem um endereço de espaço reservado de ; o endereço real usado em tempo de execução é o endereço de retorno de http://www.contoso.comchamada fornecido.

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"
        }
     }
};

Quando o StartOrder método é invocado no primeiro fluxo de trabalho, a saída a seguir é exibida, que mostra o fluxo de execução através dos dois fluxos de trabalho.

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

Neste exemplo, ambos os fluxos de trabalho gerenciam explicitamente a correlação usando um CallbackCorrelationInitializerarquivo . Como havia apenas uma única correlação nesses fluxos de trabalho de exemplo, o gerenciamento padrão CorrelationHandle teria sido suficiente.