Compartilhar via


Solução de problemas de correlação

A correlação é usada para relacionar mensagens de serviço de fluxo de trabalho entre si e à instância de fluxo de trabalho correta, mas se ela não estiver configurada corretamente, as mensagens não serão recebidas e os aplicativos não funcionarão corretamente. Este tópico fornece uma visão geral de vários métodos para solucionar problemas de correlação e também lista alguns problemas comuns que podem ocorrer quando você usa correlação.

Manipular o evento UnknownMessageReceived

O UnknownMessageReceived evento ocorre quando uma mensagem desconhecida é recebida por um serviço, incluindo mensagens que não podem ser correlacionadas a uma instância existente. Para serviços auto-hospedados, esse evento pode ser tratado no aplicativo host.

host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
    Console.WriteLine("Unknown Message Received:");
    Console.WriteLine(e.Message);
};

Para serviços hospedados na Web, esse evento pode ser tratado derivando uma classe de WorkflowServiceHostFactory e substituindo 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;
    }
}

Esse WorkflowServiceHostFactory personalizado pode ser especificado no arquivo svc para serviço.

<% @ServiceHost Language="C#" Service="OrderServiceWorkflow" Factory="CustomFactory" %>

Quando esse manipulador é invocado, a mensagem pode ser recuperada usando 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>

Inspecionar mensagens enviadas para o UnknownMessageReceived manipulador pode fornecer pistas sobre por que a mensagem não se correlaciona com uma instância do serviço de fluxo de trabalho.

Usar o acompanhamento para monitorar o progresso do fluxo de trabalho

O acompanhamento fornece uma maneira de monitorar o progresso de um fluxo de trabalho. Por padrão, os registros de acompanhamento são emitidos para eventos do ciclo de vida do fluxo de trabalho, eventos do ciclo de vida da atividade, propagação de falhas e retomada do marcador. Além disso, os registros de acompanhamento personalizados podem ser emitidos por atividades personalizadas. Ao solucionar problemas de correlação, os registros de acompanhamento de atividades, os registros de retomada do marcador e os registros de propagação de falha são os mais úteis. Os registros de acompanhamento de atividades podem ser usados para determinar o progresso atual do fluxo de trabalho e podem ajudar a identificar qual atividade de mensagens está atualmente aguardando mensagens. Os registros de retomada do marcador são úteis porque indicam que uma mensagem foi recebida pelo fluxo de trabalho, e os registros de propagação de falhas documentam quaisquer falhas no fluxo de trabalho. Para habilitar o acompanhamento, especifique o desejado TrackingParticipant no WorkflowExtensions do WorkflowServiceHost. No exemplo a seguir, o ConsoleTrackingParticipant (do exemplo de Acompanhamento Personalizado ) é configurado usando o perfil de acompanhamento padrão.

host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());

Um participante de acompanhamento, como o ConsoleTrackingParticipant, é útil para serviços de fluxo de trabalho auto-hospedados que têm uma janela de console. Para um serviço hospedado na Web, deve ser utilizado um participante de rastreamento que registre as informações de rastreamento em um armazenamento durável, como o interno EtwTrackingParticipant, ou um participante de rastreamento personalizado que registre as informações em um arquivo.

Para obter mais informações sobre como rastrear e configurar o rastreamento para um serviço de fluxo de trabalho hospedado na Web, consulte Rastreamento e Rastreamento de Fluxo de Trabalho, Configuração do Rastreamento para um Fluxo de Trabalho e os exemplos de Tracking [Exemplos do WF].

Usar o rastreamento do WCF

O rastreamento WCF fornece o rastreamento do fluxo de mensagens de e para um serviço de fluxo de trabalho. Essas informações de rastreamento são úteis ao solucionar problemas de correlação, especialmente para correlação baseada em conteúdo. Para habilitar o rastreamento, especifique os ouvintes de rastreamento desejados na seção system.diagnostics do arquivo web.config, se o serviço de fluxo de trabalho estiver hospedado na Web, ou no arquivo app.config, se o serviço de fluxo de trabalho for auto-hospedado. Para incluir o conteúdo das mensagens no arquivo de rastreamento, especifique true para logEntireMessage no elemento messageLogging na seção diagnostics de system.serviceModel. No exemplo a seguir, as informações de rastreamento, incluindo o conteúdo das mensagens, são configuradas para serem gravadas em um arquivo nomeado 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 exibir as informações de rastreamento contidas service.svclog, a Ferramenta visualizador de rastreamento de serviço (SvcTraceViewer.exe) é usada. Isso é especialmente útil ao resolver problemas de correlação baseada em conteúdo, porque você pode exibir o conteúdo da mensagem e observar exatamente o que está sendo transmitido e se corresponde à CorrelationQuery correlação baseada em conteúdo. Para obter mais informações sobre o rastreamento do WCF, consulte Service Trace Viewer Tool (SvcTraceViewer.exe), Configurando o Rastreamento e Usando o Rastreamento para Solucionar Problemas em Seu Aplicativo.

Problemas comuns de correlação na Troca de Contexto

Determinados tipos de correlação exigem que um tipo específico de associação seja usado para que a correlação funcione corretamente. Os exemplos incluem a correlação solicitação-resposta, que requer uma associação bidirecional, como BasicHttpBinding, e correlação de troca de contexto, que requer uma associação baseada em contexto, como BasicHttpContextBinding. A maioria das associações dá suporte a operações bidirecionais, portanto, esse não é um problema comum para correlação solicitação-resposta, mas há apenas um punhado de associações baseadas em contexto, incluindo BasicHttpContextBinding, WSHttpContextBindinge NetTcpContextBinding. Se uma dessas associações não for usada, a chamada inicial para um serviço de fluxo de trabalho terá êxito, 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 usadas para correlação de contexto podem ser retornadas pela SendReply à Receive atividade que inicializa a correlação de contexto ao usar uma operação bidirecional, ou podem ser especificadas pelo chamador se a operação for unidirecional. Se o contexto não for enviado pelo chamador ou retornado pelo serviço de fluxo de trabalho, o mesmo FaultException descrito anteriormente será retornado quando uma operação subsequente for invocada.

Problemas comuns de correlação de Requisição-Resposta

A correlação solicitação-resposta é usada com um Receive/SendReply par para implementar uma operação bidirecional em um serviço de fluxo de trabalho e com um Send/ReceiveReply par que invoca uma operação bidirecional em outro serviço Web. Ao invocar uma operação bidirecional em um serviço WCF, o serviço pode ser um serviço WCF tradicional baseado em código ou pode ser um serviço de fluxo de trabalho. Para usar a correlação solicitação-resposta, uma associação bidirecional deve ser usada, como BasicHttpBinding, e as operações devem ser bidirecionais.

Se o serviço de fluxo de trabalho tiver operações bidirecionais em paralelo ou sobrepostas Receive/SendReply ou Send/ReceiveReply pares, o gerenciamento de identificador de correlação implícita fornecido por WorkflowServiceHost pode não ser suficiente, especialmente em cenários de alto estresse, e as mensagens podem não ser roteadas corretamente. Para evitar que esse problema ocorra, recomendamos que você sempre especifique explicitamente um CorrelationHandle na correlação solicitação-resposta ao usar. Ao usar os modelos SendAndReceiveReply e ReceiveAndSendReply da seção Mensagens da Caixa de Ferramentas no designer de fluxo de trabalho, um CorrelationHandle é configurado explicitamente por padrão. Ao criar um fluxo de trabalho usando o código, CorrelationHandle é especificado na primeira atividade do par CorrelationInitializers. No exemplo Receiveseguinte, uma atividade CorrelationHandle é configurada com uma RequestReplyCorrelationInitializer especificação explícita especificada em .

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 par de Receive/SendReply ou um par de Send/ReceiveReply. Cria-se 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 ocioso, o fluxo de trabalho não será mantido, mesmo que o host esteja configurado para manter os fluxos de trabalho quando eles ficarem ociosos. Se uma atividade, como uma atividade persistente, tentar persistir explicitamente na zona sem persistência, uma exceção fatal será gerada, o fluxo de trabalho será anulado e um FaultException será retornado ao chamador. A mensagem de exceção fatal é "System.InvalidOperationException: atividades persistentes não podem ser contidas em nenhum bloco de persistência". Essa exceção não é retornada ao chamador, mas pode ser observada se o rastreamento estiver habilitado. A mensagem retornada ao FaultException chamador é "A operação não pôde ser permitida porque a WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' foi concluída".

Para obter mais informações sobre a correlação solicitação-resposta, consulte Request-Reply.

Problemas comuns de correlação de conteúdo

A correlação baseada em conteúdo é usada quando um serviço de fluxo de trabalho recebe várias mensagens e um pedaço de dados nas mensagens trocadas identifica a instância desejada. A correlação baseada em conteúdo usa esses dados na mensagem, como um número de cliente ou ID de pedido, para rotear mensagens para a instância correta do fluxo de trabalho. Esta seção descreve vários problemas comuns que podem ocorrer ao usar a correlação baseada em conteúdo.

Verifique se os dados de identificação são exclusivos

Os dados usados para identificar a instância são convertidos em hash em uma chave de correlação. Deve-se tomar cuidado para garantir que os dados usados para correlação sejam exclusivos ou então colisões na chave hash possam ocorrer e fazer com que as mensagens sejam mal roteadas. Por exemplo, uma correlação baseada apenas em um nome de cliente pode causar uma colisão porque pode haver vários clientes que têm o mesmo nome. Os dois-pontos (:) não devem ser usados como parte dos dados usados para correlacionar a mensagem porque ela já é usada para delimitar a chave e o valor da consulta de mensagem para formar a cadeia de caracteres que é posteriormente hashed. Se a persistência estiver sendo usada, verifique se os dados de identificação atuais não foram usados por uma instância persistida anteriormente. Desabilitar temporariamente a persistência pode ajudar a identificar esse problema. O rastreamento WCF pode ser usado para exibir a chave de correlação calculada e é útil para depurar esse tipo de problema.

Condições de corrida

Há uma pequena lacuna no tempo entre o serviço que recebe uma mensagem e a correlação realmente sendo inicializada, durante a qual as mensagens de acompanhamento serão ignoradas. Se um serviço de fluxo de trabalho inicializar a correlação baseada em conteúdo usando dados passados do cliente em uma operação unidirecional e o chamador enviar mensagens de acompanhamento imediato, essas mensagens serão ignoradas durante esse intervalo. Isso pode ser evitado usando uma operação bidirecional para inicializar a correlação ou usando um TransactedReceiveScope.

Problemas de consulta de correlação

Consultas de correlação são usadas para especificar quais dados em uma mensagem são usados para correlacionar a mensagem. Esses dados são especificados usando uma consulta XPath. Se as mensagens para um serviço não estiverem sendo enviadas mesmo que tudo pareça estar correto, uma estratégia para soluçã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, use a string função. No exemplo a seguir, um MessageQuerySet é configurado para usar um valor literal de 11445 para o OrderId, e a consulta XPath está comentada.

MessageQuerySet = new MessageQuerySet
{
    {
        "OrderId",
        //new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
        new XPathMessageQuery("string('11445')")
    }
}

Se uma consulta XPath estiver configurada incorretamente de modo que nenhum dado de correlação seja recuperado, uma falha será retornada com a seguinte mensagem: "Uma consulta de correlação rendeu um conjunto de resultados vazio. Verifique se as consultas de correlação para o ponto de extremidade estão configuradas corretamente." Uma maneira rápida de solucionar esse problema é substituir a consulta XPath por um valor literal, conforme descrito na seção anterior. Esse problema poderá ocorrer se você usar o construtor de consultas XPath nas caixas de diálogo Adicionar Inicializadores de Correlação ou Definição CorrelatesOn e seu serviço de fluxo de trabalho usar contratos de mensagem. No exemplo a seguir, uma classe de contrato de mensagem é definida.

[MessageContract]
public class AddItemMessage
{
    [MessageHeader]
    public string CartId;

    [MessageBodyMember]
    public string Item;
}

Esse contrato de mensagem é usado por uma Receive atividade em um fluxo de trabalho. O CartId cabeçalho da mensagem é usado para correlacionar a mensagem à instância correta. Se a consulta XPath que recupera a CartId é criada usando as caixas de diálogo de correlação no designer de fluxo de trabalho, a consulta XPath incorreta a seguir será gerada.

sm:body()/xg0:AddItemMessage/xg0:CartId

Essa consulta XPath estaria correta se a Receive atividade utilizasse parâmetros para os dados, mas como ela está usando um contrato de mensagem, ela está incorreta. A consulta XPath a seguir é a consulta XPath correta para recuperar o CartId do cabeçalho.

sm:header()/tempuri:CartId

Isso pode ser confirmado examinando 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 a seguir mostra uma Receive atividade configurada para uma AddItem operação que usa 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>