Resolução de Problemas de Correlação
A correlação é utilizada para relacionar mensagens de serviço de fluxo de trabalho entre si e com a instância de fluxo de trabalho correta, mas se não estiver configurada corretamente, as mensagens não serão recebidas e as aplicações não funcionarão corretamente. Este tópico fornece uma descrição geral de vários métodos para resolver problemas de correlação e também lista alguns problemas comuns que podem ocorrer quando utiliza a correlação.
Processar o Evento UnknownMessageReceived
O UnknownMessageReceived evento ocorre quando uma mensagem desconhecida é recebida por um serviço, incluindo mensagens que não podem ser correlacionadas com uma instância existente. Para serviços autoalojados, este evento pode ser processado na aplicação anfitriã.
host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
Console.WriteLine("Unknown Message Received:");
Console.WriteLine(e.Message);
};
Para serviços alojados na Web, este evento pode ser processado ao derivar uma classe de WorkflowServiceHostFactory e substituir 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;
}
}
Esta personalização WorkflowServiceHostFactory pode, em seguida, ser especificada no svc
ficheiro do serviço.
<% @ServiceHost Language="C#" Service="OrderServiceWorkflow" Factory="CustomFactory" %>
Quando este processador é invocado, a mensagem pode ser obtida com a Message propriedade do UnknownMessageReceivedEventArgse será semelhante à seguinte mensagem.
<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>
A inspeção de mensagens enviadas para o UnknownMessageReceived processador pode fornecer pistas sobre o motivo pelo qual a mensagem não se correlacionou com uma instância do serviço de fluxo de trabalho.
Utilizar o Controlo para Monitorizar o Progresso do Fluxo de Trabalho
O controlo fornece uma forma de monitorizar o progresso de um fluxo de trabalho. Por predefinição, os registos de controlo são emitidos para eventos do ciclo de vida do fluxo de trabalho, eventos de ciclo de vida de atividade, propagação de falhas e reinício de marcadores. Além disso, os registos de controlo personalizados podem ser emitidos por atividades personalizadas. Ao resolver problemas de correlação, os registos de controlo de atividade, os registos de reativação de marcadores e os registos de propagação de falhas são os mais úteis. Os registos de controlo de atividades podem ser utilizados para determinar o progresso atual do fluxo de trabalho e podem ajudar a identificar que atividade de mensagens está atualmente à espera de mensagens. Os registos de reativação de marcadores são úteis porque indicam que uma mensagem foi recebida pelo fluxo de trabalho e os registos de propagação de falhas fornecem um registo de quaisquer falhas no fluxo de trabalho. Para ativar o controlo, especifique o pretendido TrackingParticipant no WorkflowExtensions de WorkflowServiceHost. No exemplo seguinte, o ConsoleTrackingParticipant
(a partir do exemplo de Controlo Personalizado ) é configurado com o perfil de controlo predefinido.
host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());
Um participante de controlo, como ConsoleTrackingParticipant, é útil para serviços de fluxo de trabalho autoalojados que têm uma janela de consola. Para um serviço alojado na EtwTrackingParticipantWeb, deve ser utilizado um participante de controlo que registe as informações de controlo num arquivo durável, como o incorporado ou um participante de controlo personalizado que regista as informações num ficheiro.
Para obter mais informações sobre como controlar e configurar o controlo de um serviço de fluxo de trabalho alojado na Web, veja Rastreio e Rastreio de Fluxos de Trabalho, Configurar o Controlo para um Fluxo de Trabalho e os exemplos de Controlo [WF Samples ].
Utilizar o Rastreio de WCF
O rastreio do WCF fornece o rastreio do fluxo de mensagens de e para um serviço de fluxo de trabalho. Estas informações de rastreio são úteis para resolver problemas de correlação, especialmente para correlação baseada em conteúdos. Para ativar o rastreio, especifique os serviços de escuta de rastreio pretendidos na system.diagnostics
secção do web.config
ficheiro se o serviço de fluxo de trabalho estiver alojado na Web ou o app.config
ficheiro se o serviço de fluxo de trabalho estiver autoalojado. Para incluir o conteúdo das mensagens no ficheiro de rastreio, especifique true
para logEntireMessage
no messageLogging
elemento na diagnostics
secção de system.serviceModel
. No exemplo seguinte, as informações de rastreio, incluindo o conteúdo das mensagens, estão configuradas para serem escritas num ficheiro com o nome 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>
Para ver as informações de rastreio contidas no service.svclog
, é utilizada a Ferramenta de Visualizador de Rastreio de Serviços (SvcTraceViewer.exe ). Isto é especialmente útil ao resolver problemas de correlação baseados em conteúdos, uma vez que pode ver o conteúdo da mensagem e ver exatamente o que está a ser transmitido e se corresponde ao CorrelationQuery da correlação baseada em conteúdos. Para obter mais informações sobre o rastreio de WCF, veja Service Trace Viewer Tool (SvcTraceViewer.exe), Configuring Tracing e Using Tracing to Troubleshoot Your Application (Configurar o Rastreio e Utilizar o Rastreio para Resolver Problemas da Sua Aplicação).
Problemas comuns de Correlação do Exchange de Contexto
Determinados tipos de correlação requerem que seja utilizado um tipo específico de enlace para que a correlação funcione corretamente. Os exemplos incluem a correlação pedido-resposta, que requer um enlace bidirecional, como BasicHttpBinding, e a correlação de troca de contexto, que requer um enlace baseado no contexto, como BasicHttpContextBinding. A maioria dos enlaces suporta operações bidirecionais, pelo que este não é um problema comum para a correlação pedido-resposta, mas existem apenas alguns enlaces baseados no contexto, incluindo BasicHttpContextBinding, WSHttpContextBindinge NetTcpContextBinding. Se um destes enlaces não for utilizado, a chamada inicial para um serviço de fluxo de trabalho será bem-sucedida, mas as chamadas subsequentes falharão com o seguinte 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.
As informações de contexto utilizadas para a correlação de contexto podem ser devolvidas pela SendReplyReceive atividade que inicializa a correlação de contexto ao utilizar uma operação bidirecional ou pode ser especificada pelo autor da chamada se a operação for unidirecional. Se o contexto não for enviado pelo autor da chamada ou devolvido pelo serviço de fluxo de trabalho, o mesmo FaultException descrito anteriormente será devolvido quando uma operação subsequente for invocada.
Problemas comuns de correlação de Request-Reply
A correlação pedido-resposta é utilizada com um Receive/SendReply par para implementar uma operação bidirecional num serviço de fluxo de trabalho e com um Send/ReceiveReply par que invoca uma operação bidirecional noutro serviço Web. Ao invocar uma operação bidirecional num serviço WCF, o serviço pode ser um serviço WCF tradicional baseado em código imperativo ou pode ser um serviço de fluxo de trabalho. Para utilizar a correlação pedido-resposta, tem de ser utilizado um enlace bidirecional, como BasicHttpBinding, e as operações têm de ser bidirecionais.
Se o serviço de fluxo de trabalho tiver operações bidirecionais em paralelo, ou sobrepostos Receive/SendReply ouReceiveReplySend/pares, a gestão implícita do identificador de correlação fornecida pelo WorkflowServiceHost pode não ser suficiente, especialmente em cenários de alto stress, e as mensagens podem não ser encaminhadas corretamente. Para impedir que este problema ocorra, recomendamos que especifique sempre explicitamente uma CorrelationHandle ao utilizar a correlação pedido-resposta. Ao utilizar os modelos SendAndReceiveReply e ReceiveAndSendReply da secção Mensagens da Caixa de Ferramentas no estruturador de fluxo de trabalho, um CorrelationHandle é explicitamente configurado por predefinição. Ao criar um fluxo de trabalho com código, o CorrelationHandle é especificado na CorrelationInitializers primeira atividade no par. No exemplo seguinte, uma Receive atividade é configurada com uma especificação explícita CorrelationHandle no 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.
A persistência não é permitida entre um Receive/SendReply par ou um Send/ReceiveReply par. É criada uma zona sem persistência que dura até ambas as atividades serem concluídas. Se uma atividade, como uma atividade de atraso, estiver nesta zona sem persistência e fizer com que o fluxo de trabalho fique inativo, o fluxo de trabalho não persistirá mesmo que o anfitrião esteja configurado para manter os fluxos de trabalho quando ficarem inativos. Se uma atividade, como uma atividade persistida, tentar persistir explicitamente na zona sem persistência, é emitida uma exceção fatal, o fluxo de trabalho aborta e é FaultException devolvido ao autor da chamada. A mensagem de exceção fatal é "System.InvalidOperationException: Persist activities cannot be contained within no persistence blocks.". Esta exceção não é devolvida ao autor da chamada, mas pode ser observada se o controlo estiver ativado. A mensagem do FaultException devolvido ao autor da chamada é "Não foi possível executar a operação porque a WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' foi concluída".
Para obter mais informações sobre a correlação pedido-resposta, veja Request-Reply.
Problemas Comuns de Correlação de Conteúdo
A correlação baseada em conteúdo é utilizada quando um serviço de fluxo de trabalho recebe várias mensagens e um conjunto de dados nas mensagens trocadas identifica a instância pretendida. A correlação baseada em conteúdo utiliza estes dados na mensagem, como um número de cliente ou ID de encomenda, para encaminhar mensagens para a instância de fluxo de trabalho correta. Esta secção descreve vários problemas comuns que podem ocorrer ao utilizar a correlação baseada em conteúdos.
Certifique-se de que a Identificação de Dados é Exclusiva
Os dados utilizados para identificar a instância são transformados num hash numa chave de correlação. Deve ter cuidado para garantir que os dados utilizados para correlação são exclusivos ou caso contrário podem ocorrer colisões na chave hash e fazer com que as mensagens sejam mal redirecionadas. Por exemplo, uma correlação baseada apenas no nome de um cliente pode causar uma colisão porque podem existir vários clientes com o mesmo nome. Os dois pontos (:) não deve ser utilizado como parte dos dados que são utilizados para correlacionar a mensagem porque já é utilizado para delimitar a chave e o valor da consulta da mensagem para formar a cadeia de carateres que é posteriormente hashada. Se estiver a ser utilizada persistência, confirme que os dados de identificação atuais não foram utilizados por uma instância persistente anteriormente. Desativar temporariamente a persistência pode ajudar a identificar este problema. O rastreio de WCF pode ser utilizado para ver a chave de correlação calculada e é útil para depurar este tipo de problema.
Condições de Corrida
Existe um pequeno intervalo de tempo entre o serviço que recebe uma mensagem e a correlação realmente a ser inicializada, durante a qual as mensagens de seguimento serão ignoradas. Se um serviço de fluxo de trabalho inicializar a correlação baseada em conteúdos através de dados transmitidos pelo cliente através de uma operação unidirecional e o autor da chamada enviar mensagens de seguimento imediatas, estas mensagens serão ignoradas durante este intervalo. Isto pode ser evitado com uma operação bidirecional para inicializar a correlação ou com um TransactedReceiveScope.
Problemas de Consulta de Correlação
As consultas de correlação são utilizadas para especificar que dados numa mensagem são utilizados para correlacionar a mensagem. Estes dados são especificados através de uma consulta XPath. Se as mensagens para um serviço não estiverem a ser enviadas, apesar de tudo parecer estar correto, uma estratégia para a resolução de problemas é especificar um valor literal que corresponda ao valor dos dados da mensagem em vez de uma consulta XPath. Para especificar um valor literal, utilize a string
função . No exemplo seguinte, um MessageQuerySet está configurado para utilizar um valor literal de 11445
para e OrderId
a consulta XPath é comentada.
MessageQuerySet = new MessageQuerySet
{
{
"OrderId",
//new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
new XPathMessageQuery("string('11445')")
}
}
Se uma consulta XPath estiver configurada incorretamente para que não sejam obtidos dados de correlação, é devolvida uma falha com a seguinte mensagem: "Uma consulta de correlação deu origem a um conjunto de resultados vazio. Certifique-se de que as consultas de correlação para o ponto final estão configuradas corretamente." Uma forma rápida de resolver este problema é substituir a consulta XPath por um valor literal, conforme descrito na secção anterior. Este problema pode ocorrer se utilizar o construtor de consultas XPath nas caixas de diálogo Adicionar Inicializadores de Correlação ou CorrelatesOn Definition e o seu serviço de fluxo de trabalho utilizar contratos de mensagens. No exemplo seguinte, é definida uma classe de contrato de mensagem.
[MessageContract]
public class AddItemMessage
{
[MessageHeader]
public string CartId;
[MessageBodyMember]
public string Item;
}
Este contrato de mensagem é utilizado por uma Receive atividade num fluxo de trabalho. O CartId
no cabeçalho da mensagem é utilizado para correlacionar a mensagem com a instância correta. Se a consulta XPath que obtém o CartId
for criada com as caixas de diálogo de correlação no estruturador de fluxo de trabalho, é gerada a seguinte consulta XPath incorreta.
sm:body()/xg0:AddItemMessage/xg0:CartId
Esta consulta XPath estaria correta se a Receive atividade utilizasse parâmetros para os dados, mas uma vez que está a utilizar um contrato de mensagem, está incorreta. A seguinte consulta XPath é a consulta XPath correta para obter o CartId
do cabeçalho.
sm:header()/tempuri:CartId
Isto pode ser confirmado ao examinar o corpo da mensagem.
<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>
O exemplo seguinte mostra uma Receive atividade configurada para uma AddItem
operação que utiliza o contrato de mensagem anterior para receber dados. A consulta XPath está configurada corretamente.
<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>