Compartir a través de


Dúplex duradero

Este tema es aplicable a Windows Workflow Foundation 4.

La correlación dúplex duradera, también conocida como correlación de devolución de llamada, es útil cuando un servicio de flujo de trabajo tiene un requisito para enviar una devolución de llamada al autor de la llamada inicial. A diferencia del dúplex de WCF, la devolución de llamada puede producirse en cualquier momento en el futuro y no está vinculada a un mismo canal o a la duración del canal; el único requisito es que el autor de la llamada tenga un extremo activo que realice escuchas para el mensaje de devolución de llamada. Esto permite a dos servicios de flujo de trabajo comunicarse en una conversación de ejecución prolongada. En este tema, se proporciona información general sobre la correlación dúplex duradera.

Usar la correlación dúplex duradera

Para usar la correlación dúplex duradera, los dos servicios deben usar un enlace habilitado para el contexto que admita operaciones bidireccionales, como NetTcpContextBinding o WSHttpContextBinding. El servicio de llamada registra ClientCallbackAddress con el enlace deseado en Endpoint del cliente. El servicio de recepción recibe estos datos en la llamada inicial y, a continuación, los usa en su propia Endpoint, en la actividad Send que realiza la devolución de llamada al servicio de llamada. En este ejemplo, dos servicios se comunican entre sí. El primer servicio invoca un método en el segundo servicio y, a continuación, espera una respuesta. El segundo servicio conoce el nombre del método de devolución de llamada, pero no conoce el extremo del servicio que implementa este método en tiempo de diseño. En el siguiente ejemplo, se hospeda un servicio de flujo de trabajo que crea una Endpoint de devolución de llamada mediante WSHttpContextBinding.

// Host WF Service 1.
string baseAddress1 = "https://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);

El flujo de trabajo que implementa este servicio de flujo de trabajo inicializa la correlación de devolución de llamada con su actividad Send y hace referencia a este extremo de devolución de llamada de la actividad Receive que se relaciona con Send. En el siguiente ejemplo, se representa el flujo de trabajo que se devuelve del método 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("https://localhost:8081/Service2"),
        Binding = new WSHttpContextBinding
        {
            ClientCallbackAddress = new Uri("https://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"
        }
     }
};

El segundo servicio de flujo de trabajo se hospeda mediante un enlace proporcionado por sistema, con un enlace basado en el contexto.

// Host WF Service 2.
string baseAddress2 = "https://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);

El flujo de trabajo que implementa este servicio de flujo de trabajo comienza con una actividad Receive. Esta actividad de recepción inicializa la correlación de devolución de llamada para este servicio, se retrasa durante un período de tiempo para simular un trabajo de ejecución prolongada y, a continuación, vuelve a llamar al primer servicio mediante el contexto de devolución de llamada que se pasó en la primera llamada al servicio. En el siguiente ejemplo, se representa el flujo de trabajo que se devuelve de una llamada a GetWF2. Tenga en cuenta que la actividad Send tiene una dirección de marcador de posición https://www.contoso.com; la dirección real usada en el tiempo de ejecución es la dirección de devolución de llamada proporcionada.

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("https://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"
        }
     }
};

Cuando se invoca el método StartOrder en el primer flujo de trabajo, se muestra el siguiente resultado, que muestra el flujo de ejecución a través de los dos flujos de trabajo.

Service1 waiting at: https://localhost:8080/Service1Service2 waiting at: https://localhost:8081/Service2Press enter to exit.WF1 - StartedWF2 - Request ReceivedWF1 - Request SubmittedWF2 - Sending itemsWF2 - Items sentWF1 - Items Received

En este ejemplo, ambos flujos de trabajo administran explícitamente la correlación mediante una clase CallbackCorrelationInitializer. Dado que solo hubo una correlación única en los flujos de trabajo de este ejemplo, la administración CorrelationHandle predeterminada habría sido suficiente.