Udostępnij za pośrednictwem


Niezawodna korelacja dwukierunkowa

Trwała korelacja dwukierunkowa, znana również jako korelacja wywołania zwrotnego, jest przydatna, gdy usługa przepływu pracy wymaga wysłania wywołania zwrotnego do początkowego obiektu wywołującego. W przeciwieństwie do dwukierunkowego programu WCF wywołanie zwrotne może nastąpić w dowolnym momencie w przyszłości i nie jest powiązane z tym samym kanałem ani okresem istnienia kanału. Jedynym wymaganiem jest to, że obiekt wywołujący ma aktywny punkt końcowy nasłuchujący komunikatu wywołania zwrotnego. Dzięki temu dwie usługi przepływu pracy mogą komunikować się w długotrwałej konwersacji. Ten artykuł zawiera omówienie trwałej korelacji dwukierunkowej.

Korzystanie z trwałej korelacji dwukierunkowej

Aby korzystać z trwałej korelacji dwukierunkowej, obie usługi muszą używać powiązania obsługującego kontekst, który obsługuje operacje dwukierunkowe, takie jak NetTcpContextBinding lub WSHttpContextBinding. Usługa wywołująca rejestruje element z żądanym powiązaniem na kliencie ClientCallbackAddressEndpoint. Usługa odbierająca odbiera te dane w początkowym wywołaniu, a następnie używa ich samodzielnie Endpoint w Send działaniu, które wykonuje wywołanie z powrotem do usługi wywołującej. W tym przykładzie dwie usługi komunikują się ze sobą. Pierwsza usługa wywołuje metodę w drugiej usłudze, a następnie czeka na odpowiedź. Druga usługa zna nazwę metody wywołania zwrotnego, ale punkt końcowy usługi implementujący tę metodę nie jest znany w czasie projektowania.

Uwaga

Trwały dwukierunkowy można używać tylko wtedy, gdy AddressingVersion punkt końcowy jest skonfigurowany za pomocą WSAddressing10polecenia . Jeśli tak nie jest, InvalidOperationException zostanie zgłoszony wyjątek z następującym komunikatem: "Komunikat zawiera nagłówek kontekstu wywołania zwrotnego z odwołaniem do punktu końcowego dla elementu AddressingVersion. Kontekst wywołania zwrotnego można przesyłać tylko wtedy, gdy wersja adresowania jest skonfigurowana za pomocą polecenia "WSAddressing10".

W poniższym przykładzie hostowana jest usługa przepływu pracy, która tworzy wywołanie zwrotne Endpoint przy użyciu polecenia 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);

Przepływ pracy, który implementuje tę usługę przepływu pracy, inicjuje korelację wywołania zwrotnego z jego Send działaniem i odwołuje się do tego punktu końcowego wywołania zwrotnego z Receive działania, które jest skorelowane z Send. Poniższy przykład reprezentuje przepływ pracy zwracany z GetWF1 metody .

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

Druga usługa przepływu pracy jest hostowana przy użyciu powiązania opartego na kontekście dostarczonego przez system.

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

Przepływ pracy, który implementuje tę usługę Receive przepływu pracy, rozpoczyna się od działania. To działanie odbierające inicjuje korelację wywołania zwrotnego dla tej usługi, opóźnia się przez pewien czas, aby symulować długotrwałą pracę, a następnie wywołuje z powrotem do pierwszej usługi przy użyciu kontekstu wywołania zwrotnego, który został przekazany w pierwszym wywołaniu do usługi. W poniższym przykładzie przedstawiono przepływ pracy zwracany z wywołania metody .GetWF2 Działanie Send ma adres zastępczy ; rzeczywisty adres http://www.contoso.comużywany w czasie wykonywania jest podanym adresem wywołania zwrotnego.

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 Po wywołaniu metody w pierwszym przepływie pracy zostaną wyświetlone następujące dane wyjściowe, które pokazują przepływ wykonywania za pośrednictwem dwóch przepływów pracy.

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

W tym przykładzie oba przepływy pracy jawnie zarządzają korelacją przy użyciu elementu CallbackCorrelationInitializer. Ponieważ w tych przykładowych przepływach pracy istniała tylko jedna korelacja, domyślne CorrelationHandle zarządzanie byłoby wystarczające.