Condividi tramite


Duplex durevole

Le informazioni contenute in questo argomento sono valide per Windows Workflow Foundation 4.

La correlazione duplex durevole, nota anche come correlazione di callback, risulta utile se un servizio flusso di lavoro dispone del requisito adatto a inviare un callback al chiamante iniziale. A differenza del duplex WCF, il callback si può verificare in qualsiasi momento nel futuro e non è legato allo stesso canale o al canale di durata. L'unico requisito è costituito dal fatto che il chiamante dispone di un endpoint attivo in ascolto del messaggio di callback. In questo modo due servizi flusso di lavoro possono comunicare in una conversazione prolungata. In questo argomento vengono forniti cenni preliminari sulla correlazione duplex durevole.

Utilizzo della correlazione duplex durevole

Per utilizzare la correlazione duplex durevole, i due servizi devono utilizzare un'associazione abilitata per il contesto che supporta operazioni bidirezionali, ad esempio NetTcpContextBinding o WSHttpContextBinding. Il servizio chiamante registra un ClientCallbackAddress con l'associazione desiderata sul client Endpoint. Il servizio ricevente riceve questi dati nella chiamata iniziale, quindi li utilizza sul proprio Endpoint nell'attività Send che effettua nuovamente la chiamata al servizio chiamante. In questo esempio, due servizi comunicano l'uno con l'altro. Il primo servizio richiama un metodo nel secondo servizio, quindi attende una risposta. Il secondo servizio conosce il nome del metodo di callback, ma l'endpoint del servizio che implementa questo metodo non è noto in fase di progettazione. Nell'esempio seguente viene ospitato un servizio flusso di lavoro che crea un Endpoint del callback 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);

Il flusso di lavoro che implementa questo servizio flusso di lavoro inizializza la correlazione di callback con l'attività Send e fa riferimento a questo endpoint di callback dall'attività Receive correlata all'elemento Send. Nell'esempio seguente viene rappresentato il flusso di lavoro restituito dal metodo 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"
        }
     }
};

Il secondo servizio flusso di lavoro viene ospitato utilizzando un'associazione fornita dal sistema e basata sul contesto.

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

Il flusso di lavoro che implementa questo servizio flusso di lavoro inizia con un'attività Receive. Questa attività di ricezione inizializza la correlazione di callback per questo servizio, ritarda per un periodo di tempo al fine di simulare un lavoro dall'esecuzione prolungata, quindi esegue una nuova chiamata nel primo servizio utilizzando il contesto di callback passato nella prima chiamata nel servizio. Nell'esempio seguente viene rappresentato il flusso di lavoro restituito da una chiamata a GetWF2. L'attività Send dispone di un indirizzo del segnaposto https://www.contoso.com. L'indirizzo effettivo utilizzato al runtime coincide con l'indirizzo di callback fornito.

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

Quando il metodo StartOrder viene richiamato nel primo flusso di lavoro, viene visualizzato l'output seguente che indica il flusso di esecuzione tramite i due flussi di lavoro.

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

In questo esempio, entrambi i flussi di lavoro gestiscono in modo esplicito la correlazione mediante un CallbackCorrelationInitializer. Poiché in questi flussi di lavoro di esempio era presente una sola correlazione, sarebbe stata sufficiente la gestione di CorrelationHandle predefinita.