Поделиться через


Сохраняемая дуплексная корреляция

Сохраняемую дуплексную корреляцию, также называемую корреляцией обратных вызовов, удобно использовать, когда служба рабочего процесса должна отправлять обратный вызов исходному вызывающему объекту. В отличие от дуплексного wcF, обратный вызов может произойти в любое время в будущем и не привязан к одному каналу или времени существования канала. Единственное требование заключается в том, что вызывающий объект имеет активную конечную точку, прослушивающую сообщение обратного вызова. Благодаря этому обеспечивается возможность взаимодействия двух служб рабочего процесса в долговременных диалогах. В этой статье представлен обзор устойчивой дуплексной корреляции.

Использование сохраняемой дуплексной корреляции

Чтобы использовать сохраняемую дуплексную корреляцию, две службы должны использовать контекстную привязку, которая поддерживает двусторонние операции, такие как NetTcpContextBinding или WSHttpContextBinding. Вызывающая служба регистрирует ClientCallbackAddress с привязкой на их клиентской конечной точке Endpoint. Принимающая служба получает эти данные в первоначальном вызове, а затем использует их для собственных Endpoint в действии Send, выполняющем обратный вызов вызывающей службы. В этом примере две службы взаимодействуют друг с другом. Первая служба вызывает метод для второй службы, а затем ожидает ответа. Вторая служба знает имя метода обратного вызова, но конечная точка службы, реализующая этот метод, не известна во время разработки.

Примечание.

Сохраняемая дуплексная корреляция может быть использована только в случае, если параметр AddressingVersion конечной точки установлен в значение WSAddressing10. Если это не так, InvalidOperationException исключение создается со следующим сообщением: "Сообщение содержит заголовок контекста обратного вызова с ссылкой на конечную точку для AddressingVersion. Контекст обратного вызова может передаваться только при настройке Адресации с параметром WSAddressing10".

В следующем примере выполняется размещение службы рабочего процесса, с помощью которой создается обратный вызов Endpoint с помощью привязки 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);

Рабочий процесс, реализующий эту службу рабочего процесса, инициализирует корреляцию обратного вызова со своим действием Send и ссылается на эту конечную точку обратного вызова из действия Receive, для которого выполнена корреляция с действием Send. В следующем примере представлен рабочий процесс, который возвращается из метода 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("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"
        }
     }
};

Вторая служба рабочего процесса размещается с использованием предоставленной системой контекстной привязки.

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

Рабочий процесс, реализующий эту службу рабочего процесса, начинается с действия Receive. Это действие получения инициализирует корреляцию обратного вызова для этой службы, откладывает выполнение на определенный период времени для моделирования долгосрочных работ, а затем выполняет обратный вызов в первую службу с использованием контекста обратного вызова, переданного в первом вызове в службу. В следующем примере представлен рабочий процесс, который возвращается из вызова GetWF2. Действие Send имеет адрес http://www.contoso.comзаполнителя; фактический адрес, используемый во время выполнения, является предоставленным адресом обратного вызова.

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 в первом рабочем процессе отображается следующий результат, в котором показан ход выполнения с двумя рабочими процессами.

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

В этом примере оба рабочих процесса явно управляют корреляцией с помощью объекта CallbackCorrelationInitializer. Поскольку в этих образцах имеется только одна корреляция, настройки управления CorrelationHandle, заданные по умолчанию, не требуют изменений.