Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Корреляция используется для связи сообщений службы рабочих процессов друг с другом и правильного экземпляра рабочего процесса, но если он не настроен правильно, сообщения не будут получены, а приложения не будут работать правильно. В этом разделе представлен обзор нескольких методов устранения проблем корреляции, а также перечислены некоторые распространенные проблемы, которые могут возникать при использовании корреляции.
Обработайте событие UnknownMessageReceived
Это UnknownMessageReceived событие происходит, когда сервис получает неизвестное сообщение, включая сообщения, которые не могут быть сопоставлены с существующим экземпляром. Для локальных служб это событие можно обрабатывать в хост-приложении.
host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
Console.WriteLine("Unknown Message Received:");
Console.WriteLine(e.Message);
};
Для веб-размещенных служб это событие можно обрабатывать путем извлечения класса из WorkflowServiceHostFactory и переопределения CreateWorkflowServiceHost.
class CustomFactory : WorkflowServiceHostFactory
{
protected override WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)
{
// Create the WorkflowServiceHost.
WorkflowServiceHost host = new WorkflowServiceHost(activity, baseAddresses);
// Handle the UnknownMessageReceived event.
host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
Console.WriteLine("Unknown Message Received:");
Console.WriteLine(e.Message);
};
return host;
}
}
Затем этот пользовательский WorkflowServiceHostFactory параметр можно указать в svc файле для службы.
<% @ServiceHost Language="C#" Service="OrderServiceWorkflow" Factory="CustomFactory" %>
При вызове этого обработчика сообщение можно получить с помощью Message свойства объекта UnknownMessageReceivedEventArgsи будет выглядеть следующим образом.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:8080/OrderService</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/AddItem</Action>
</s:Header>
<s:Body>
<AddItem xmlns="http://tempuri.org/">
<Item>Books</Item>
</AddItem>
</s:Body>
</s:Envelope>
Проверка сообщений, UnknownMessageReceived отправленных обработчику, может дать подсказки о том, почему сообщение не коррелирует с экземпляром службы рабочего процесса.
Использование отслеживания для мониторинга хода рабочего процесса
Отслеживание позволяет отслеживать ход выполнения рабочего процесса. По умолчанию записи отслеживания создаются для событий жизненного цикла рабочего процесса, событий жизненного цикла активности, распространения ошибок и возобновления закладок. Кроме того, пользовательские записи отслеживания можно создавать пользовательскими действиями. При устранении неполадок корреляции записи отслеживания действий, записи возобновления закладок и записи распространения ошибок наиболее полезны. Записи отслеживания действий можно использовать для определения текущего состояния рабочего процесса и помочь определить, какое действие по обмену сообщениями в настоящее время находится в ожидании сообщений. Записи возобновления закладок полезны, так как они указывают на то, что сообщение получено рабочим процессом, а записи распространения ошибок предоставляют запись о любых сбоях в рабочем процессе. Чтобы включить отслеживание, укажите требуемое TrackingParticipant значение в WorkflowExtensions элементе WorkflowServiceHost. В следующем примере ConsoleTrackingParticipant (из примера Пользовательское отслеживание) настраивается с помощью профиля отслеживания по умолчанию.
host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());
Участник отслеживания, такой как ConsoleTrackingParticipant, полезен для локальных служб рабочих процессов, имеющих окно консоли. Для веб-размещенной службы следует использовать участника отслеживания, который регистрирует сведения об отслеживании в устойчивое хранилище, например, встроенный EtwTrackingParticipant, или настраиваемого участника отслеживания, который записывает информацию в файл.
Дополнительные сведения об отслеживании и настройке отслеживания для службы рабочих процессов, размещенной в вебе, см. в разделе «Отслеживание и трассировка рабочих процессов», «Настройка отслеживания для рабочего процесса» и примеры отслеживания [WF Samples].
Использование трассировки WCF
Трассировка WCF обеспечивает трассировку потока сообщений в службу рабочего процесса и из нее. Эта информация трассировки полезна при устранении неполадок корреляции, особенно для корреляции на основе содержимого. Чтобы включить трассировку, укажите нужные прослушиватели трассировки в system.diagnostics разделе web.config файла, если служба рабочего процесса размещена в Интернете, или app.config файл, если служба рабочего процесса размещена самостоятельно. Чтобы включить содержимое сообщений в файл трассировки, укажите true в logEntireMessage элементе messageLoggingdiagnostics в разделе system.serviceModel. В следующем примере данные трассировки, включая содержимое сообщений, настраиваются для записи в файл с именем service.svclog.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information" propagateActivity="true">
<listeners>
<add name="corr"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="corr"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="corr" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\logs\service.svclog">
</add>
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="false"
logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="true" maxSizeOfMessageToLog="2147483647">
</messageLogging>
</diagnostics>
</system.serviceModel>
</configuration>
Для просмотра сведений трассировки, содержащихся в service.svclog, используется средство просмотра трассировки служб (SvcTraceViewer.exe). Это особенно полезно при устранении неполадок корреляции на основе содержимого, так как вы можете просмотреть содержимое сообщения и увидеть, что передается, и соответствует ли он корреляции CorrelationQuery на основе содержимого. Дополнительные сведения о трассировке WCF см. в средстве просмотра трассировки служб (SvcTraceViewer.exe), настройке трассировки и использовании трассировки для устранения неполадок с приложением.
Распространенные проблемы корреляции в контексте Exchange
Некоторые типы корреляции требуют, чтобы для правильной работы корреляции использовался определенный тип привязки. Примеры включают корреляцию запроса-ответа, которая требует двусторонней привязки, например BasicHttpBinding, и корреляции обмена контекстом, которая требует привязки на основе контекста, например BasicHttpContextBinding. Большинство привязок поддерживают двусторонние операции, поэтому это не распространенная проблема для корреляции ответа на запрос, но есть только несколько контекстных привязок, включая BasicHttpContextBinding, WSHttpContextBindingи NetTcpContextBinding. Если одна из этих привязок не используется, начальный вызов службы рабочего процесса будет выполнен успешно, но последующие вызовы завершатся ошибкой с следующим FaultException.
There is no context attached to the incoming message for the service
and the current operation is not marked with "CanCreateInstance = true".
In order to communicate with this service check whether the incoming binding
supports the context protocol and has a valid context initialized.
Сведения о контексте, используемые для корреляции контекста, могут быть возвращены SendReplyReceive действием, которое инициализирует корреляцию контекста при использовании двусторонней операции или может быть указано вызывающим объектом, если операция является одностороннее. Если контекст не отправляется вызывающим объектом или возвращается службой рабочих процессов, то при вызове последующей операции будет возвращен тот же контекст FaultException , который описан ранее.
Распространенные проблемы корреляции запрос-ответ
Корреляция "Запрос-ответ" используется с парой Receive/SendReply для осуществления двусторонней операции в службе рабочего процесса и с парой Send/ReceiveReply, чтобы вызвать двустороннюю операцию в другой веб-службе. При вызове двусторонней операции в службе WCF служба может быть либо традиционной императивной службой WCF, либо службой рабочего процесса. Чтобы использовать корреляцию "запрос-ответ", необходимо использовать двустороннюю привязку, такую как BasicHttpBinding, и операции должны быть двусторонними.
Если служба рабочих процессов имеет двусторонние операции, выполняющиеся параллельно или перекрывающиеся Receive/SendReply или Send/ReceiveReply парами, то неявного управления дескриптором корреляции, предоставляемого WorkflowServiceHost, может быть недостаточно, особенно в условиях высокого напряжения, и сообщения могут быть неправильно перенаправлены. Чтобы предотвратить возникновение этой проблемы, рекомендуется всегда явно указывать CorrelationHandle, когда используете корреляцию типа запрос-ответ. При использовании шаблонов SendAndReceiveReply и ReceiveAndSendReply из раздела "Обмен сообщениями" на Панель элементов в конструкторе рабочих процессов, CorrelationHandle конфигурируется явно по умолчанию. При создании рабочего процесса с помощью кода CorrelationHandle указывается в CorrelationInitializers первом действии в паре. В следующем примере Receive действие настраивается явным образом CorrelationHandle , указанным в примере RequestReplyCorrelationInitializer.
Variable<CorrelationHandle> RRHandle = new Variable<CorrelationHandle>();
Receive StartOrder = new Receive
{
CanCreateInstance = true,
ServiceContractName = OrderContractName,
OperationName = "StartOrder",
CorrelationInitializers =
{
new RequestReplyCorrelationInitializer
{
CorrelationHandle = RRHandle
}
}
};
SendReply ReplyToStartOrder = new SendReply
{
Request = StartOrder,
Content = ... // Contains the return value, if any.
};
// Construct a workflow using StartOrder and ReplyToStartOrder.
Сохраняемость не допускается между парой Receive/SendReply или парой Send/ReceiveReply . Создается зона без сохранения, которая сохраняется до завершения обоих действий. Если действие, например, задержка, находится в этой зоне без сохранения и приводит к простою рабочего процесса, он не будет сохранен, даже если узел настроен на сохранение рабочих процессов при их простое. Если действие, например действие сохранения, пытается явно сохраниться в зоне без сохранения, создается неустранимое исключение, рабочий процесс прерывается и FaultException возвращается вызывающему объекту. Сообщение о неустранимом исключении: "System.InvalidOperationException: действия сохранения не могут находиться в блоках без сохранения." Это исключение не возвращается вызывающему, но может наблюдаться, если включено отслеживание. Сообщение для FaultException, возвращаемое вызывающему объекту: "Не удалось выполнить операцию, так как экземпляр рабочего процесса '5836145b-7da2-49d0-a052-a49162adeab6' завершён".
Дополнительные сведения о корреляции "запрос-ответ" см. в разделе "Запрос-ответ".
Распространенные проблемы корреляции содержимого
Корреляция на основе содержимого используется, когда служба рабочего процесса получает несколько сообщений, а часть данных в обменных сообщениях определяет нужный экземпляр. Корреляция на основе содержимого использует эти данные в сообщении, например номер клиента или идентификатор заказа, для маршрутизации сообщений в правильный экземпляр рабочего процесса. В этом разделе описывается несколько распространенных проблем, которые могут возникнуть при использовании корреляции на основе содержимого.
Убедитесь, что данные идентификации уникальны
Данные, используемые для идентификации экземпляра, хэшируются в ключ корреляции. Необходимо принять меры, чтобы гарантировать, что данные, используемые для корреляции, уникальны, иначе могут возникнуть коллизии в хэшированном ключе и привести к неправильному перенаправлению сообщений. Например, корреляция, основанная только на имени клиента, может привести к столкновению, так как может быть несколько клиентов с одинаковым именем. Двоеточие (:) не следует использовать в составе данных, которые используются для сопоставления сообщения, так как он уже используется для разделителя ключа и значения запроса сообщения для формирования строки, которая впоследствии хэшируется. Если используется сохраняемость, убедитесь, что текущий идентификатор данных не использовался ранее сохраненным экземпляром. Временное отключение сохраняемости может помочь определить эту проблему. Трассировка WCF может использоваться для просмотра вычисляемого ключа корреляции и полезна для отладки такого рода проблемы.
Условия гонки
Между службой, получающей сообщение, и фактической инициализацией корреляции существует небольшой разрыв времени, в течение которого сообщения о последующих действиях будут игнорироваться. Если служба рабочего процесса инициализирует корреляцию на основе содержимого с помощью данных, переданных клиентом через одностороннюю операцию, и вызывающий отправляет немедленные последующие сообщения, эти сообщения будут игнорироваться в течение этого интервала. Это можно избежать с помощью двусторонней операции для инициализации корреляции или с помощью функции TransactedReceiveScope.
Проблемы с запросом корреляции
Запросы корреляции используются для указания того, какие данные в сообщении используются для сопоставления сообщения. Эти данные задаются с помощью запроса XPath. Если сообщения в службу не отправляются, даже если все, как представляется, правильно, одна из стратегий устранения неполадок — указать литеральное значение, соответствующее значению данных сообщения вместо запроса XPath. Чтобы указать литеральное значение, используйте функцию string . В следующем примере MessageQuerySet настроено использовать литеральное значение 11445 для OrderId, а запрос XPath закомментирован.
MessageQuerySet = new MessageQuerySet
{
{
"OrderId",
//new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
new XPathMessageQuery("string('11445')")
}
}
Если запрос XPath настроен неправильно таким образом, что данные корреляции не извлекаются, возвращается ошибка со следующим сообщением: "Запрос корреляции дал пустой результирующий набор. Убедитесь, что запросы корреляции для конечной точки настроены правильно". Одним из быстрых способов устранения неполадок является замена запроса XPath на литеральное значение, как описано в предыдущем разделе. Эта проблема может возникнуть, если вы используете построитель запросов XPath в диалоговых окнах "Добавление инициализаторов корреляции" или "Определение корреляции", и ваша служба рабочего процесса использует контракты сообщений. В следующем примере определяется класс контракта сообщения.
[MessageContract]
public class AddItemMessage
{
[MessageHeader]
public string CartId;
[MessageBodyMember]
public string Item;
}
Этот контракт сообщения используется действием Receive в рабочем процессе. В CartId заголовке сообщения используется для сопоставления сообщения с правильным экземпляром. Если запрос XPath, который извлекает CartId создается с помощью диалоговых окон корреляции в конструкторе рабочих процессов, будет создан следующий неправильный запрос XPath.
sm:body()/xg0:AddItemMessage/xg0:CartId
Этот запрос XPath был бы правильным, если бы действие Receive использовало параметры для данных, но поскольку оно использует контракт сообщения, это неверно. Следующий запрос XPath является правильным запросом XPath для получения CartId из заголовка.
sm:header()/tempuri:CartId
Это можно подтвердить, проверив текст сообщения.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/AddItem</Action>
<h:CartId xmlns:h="http://tempuri.org/">80c95b41-c98d-4660-a6c1-99412206e54c</h:CartId>
</s:Header>
<s:Body>
<AddItemMessage xmlns="http://tempuri.org/">
<Item>Books</Item>
</AddItemMessage>
</s:Body>
</s:Envelope>
В следующем примере показано действие Receive, настроенное для операции AddItem, которая использует предыдущий контракт сообщения для получения данных. Запрос XPath правильно настроен.
<Receive CorrelatesWith="[CCHandle] OperationName="AddItem" ServiceContractName="p:IService">
<Receive.CorrelatesOn>
<XPathMessageQuery x:Key="key1">
<XPathMessageQuery.Namespaces>
<ssx:XPathMessageContextMarkup>
<x:String x:Key="xg0">http://schemas.datacontract.org/2004/07/MessageContractWFService</x:String>
</ssx:XPathMessageContextMarkup>
</XPathMessageQuery.Namespaces>sm:header()/tempuri:CartId</XPathMessageQuery>
</Receive.CorrelatesOn>
<ReceiveMessageContent DeclaredMessageType="m:AddItemMessage">
<p1:OutArgument x:TypeArguments="m:AddItemMessage">[AddItemMessage]</p1:OutArgument>
</ReceiveMessageContent>
</Receive>