Partager via


Corrélation duplex durable

La corrélation duplex durable, également appelée corrélation de rappel, est utile lorsqu’un service de flux de travail a besoin d’envoyer un rappel à l’appelant initial. Contrairement au duplex WCF, le rappel peut se produire à tout moment à l’avenir et n’est pas lié au même canal ou à la durée de vie du canal. La seule exigence est que l’appelant dispose d’un point de terminaison actif à l’écoute du message de rappel. Cela permet à deux services de flux de travail de communiquer dans une conversation longue. Cet article fournit une vue d’ensemble de la corrélation duplex durable.

Utilisation de la corrélation duplex durable

Pour utiliser une corrélation duplex durable, les deux services doivent utiliser une liaison compatible avec le contexte qui prend en charge les opérations bidirectionnelles, telles que NetTcpContextBinding ou WSHttpContextBinding. Le service d’appel enregistre une propriété ClientCallbackAddress avec la liaison souhaitée sur son Endpoint client. Le service de réception reçoit ces données dans l’appel initial, puis l’utilise par lui-même Endpoint dans l’activité Send qui effectue le rappel au service appelant. Dans cet exemple, deux services communiquent entre eux. Le premier service appelle une méthode sur le deuxième service, puis attend une réponse. Le deuxième service connaît le nom de la méthode de rappel, mais le point de terminaison du service qui implémente cette méthode n’est pas connu au moment du design.

Remarque

Le duplex durable ne peut être utilisé que si le point d'accès AddressingVersion est configuré avec WSAddressing10. Si ce n’est pas le cas, une exception InvalidOperationException est levée avec le message suivant : « Le message contient un en-tête de contexte de rappel avec une référence de point de terminaison pour AddressingVersion. » Le contexte de rappel ne peut être transmis que lorsque AddressingVersion est configuré avec « WSAddressing10 ».

Dans l'exemple suivant, un service de gestion de workflow est hébergé pour créer un rappel Endpoint à l'aide de 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);

Le workflow qui implémente ce service de workflow initialise la corrélation de rappel avec son activité Send et référence ce point de terminaison de rappel à partir de l'activité Receive en corrélation avec l'activité Send. L’exemple suivant représente le flux de travail retourné par la GetWF1 méthode.

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

Le deuxième service de flux de travail est hébergé à l’aide d’une liaison basée sur le contexte fournie par le système.

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

Le processus qui implémente ce service de workflow commence par une Receive action. Cette activité de réception initialise la corrélation de rappel pour ce service, attend un certain temps pour simuler un travail de longue durée, puis rappelle dans le premier service à l'aide du contexte de rappel qui a été transmis lors du premier appel dans le service. L’exemple suivant représente le flux de travail retourné par un appel à GetWF2. L’activité Send a une adresse fictive de http://www.contoso.com ; l’adresse réelle utilisée lors de l’exécution est l’adresse de rappel fournie.

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

Lorsque la StartOrder méthode est appelée sur le premier flux de travail, la sortie suivante s’affiche, ce qui montre le flux d’exécution via les deux flux de travail.

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

Dans cet exemple, les deux workflows gèrent explicitement la corrélation à l’aide d’un CallbackCorrelationInitializer. Étant donné qu’il n’y avait qu’une seule corrélation dans ces exemples de flux de travail, la gestion par défaut CorrelationHandle aurait été suffisante.