Compartilhar via


Correlação de solução de problemas

A correlação é usada para relacionar as mensagens de serviço de fluxo de trabalho entre si e à instância de fluxo de trabalho correta, mas se não estiver configurada corretamente, as mensagens não serão recebidas e os aplicativos não funcionarão corretamente. Este tópico apresenta 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 evento UnknownMessageReceived 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 a partir de 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 o serviço.

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

Quando esse manipulador é chamado, a mensagem pode ser recuperada usando a propriedade Message de UnknownMessageReceivedEventArgs e 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 verificação de mensagens enviadas para o manipulador UnknownMessageReceived pode fornecer pistas sobre o motivo pelo qual 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 apresenta uma forma de monitorar o andamento 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 reinício do indicador. 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 atividade, os registros de reinício do indicador e os registros de propagação de falha são os mais pertinentes. Os registros de acompanhamento de atividades podem ser usados para determinar o progresso atual do fluxo de trabalho e podem ajudar a identificar a atividade de mensagens que está aguardando mensagens atualmente. Os registros de reinício do indicador são úteis porque indicam que uma mensagem foi recebida pelo fluxo de trabalho e os registros de propagação de falha oferecem um registro de falhas no fluxo de trabalho. Para habilitar o acompanhamento, especifique o TrackingParticipant desejado no WorkflowExtensions de WorkflowServiceHost. No exemplo a seguir, 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 do console. Para um serviço hospedado na Web, deve ser usado um participante de rastreamento que registra as informações de rastreamento em um repositório durável, como EtwTrackingParticipantintegrado ou um participante de rastreamento personalizado que registra as informações em um arquivo.

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

Use Rastreamento do WCF

O rastreamento do WCF fornece 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 com base no 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 o arquivo app.config se o serviço de fluxo de trabalho for auto-hospedado. Para incluir os conteúdos 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 em service.svclog, a Ferramenta de Visualizador de Rastreamento de Serviço (SvcTraceViewer.exe) é usada. É especialmente útil ao solucionar problemas de correlação com base no conteúdo, pois você pode exibir o conteúdo da mensagem e ver exatamente o que está sendo passado e se corresponde à CorrelationQuery para a correlação baseada em conteúdo. Para obter mais informações sobre o rastreamento do WCF, consulte Ferramenta do Visualizador de Rastreamento de Serviço (SvcTraceViewer.exe), Configurando o rastreamento e Usando o rastreamento para solucionar problemas no seu aplicativo.

Problemas comuns de correlação com 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. Exemplos incluem correlação solicitação-resposta, que requer uma associação bidirecional, como BasicHttpBinding, e a correlação de troca de contexto, que requer uma associação baseada em contexto, como BasicHttpContextBinding. A maioria das associações oferece suporte a operações bidirecionais, portanto, não é um problema comum para correlação solicitação-resposta, mas há apenas um grupo de associações com base no contexto, incluindo BasicHttpContextBinding, WSHttpContextBinding e 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 não ocorrem com o FaultException a seguir.

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 a correlação de contexto podem ser retornadas por SendReply à atividade Receive que inicializa a correlação de contexto ao usar uma operação bidirecional ou pode ser especificada 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 chamada.

Problemas comuns de correlação de solicitação-resposta

A correlação de solicitação/resposta é usada com um par Receive/SendReply para implementar uma operação bidirecional em um serviço de fluxo de trabalho e com um par Send/ReceiveReply que invoca uma operação bidirecional em outro serviço da Web. Ao invocar uma operação bidirecional em um serviço WCF, o serviço pode ser um serviço pode ser WCF baseado em código imperativo tradicional 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 sobrepor os pares Receive/SendReply ou Send/ReceiveReply, 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 CorrelationHandle ao usar a correlação solicitação-resposta. Ao usar os modelos SendAndReceiveReply e ReceiveAndSendReply da seção Mensagens da Caixa de Ferramentas no designer de fluxo de trabalho, CorrelationHandle é configurado explicitamente por padrão. Ao criar um fluxo de trabalho usando o código, CorrelationHandle é especificado em CorrelationInitializers na primeira atividade do par. No exemplo a seguir, uma atividade Receive é configurada com um CorrelationHandle explícito especificado em 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.

Não é permitida persistência entre um par Receive/SendReply ou um par Send/ReceiveReply. Uma zona sem persistência é criada e dura até que ambas as atividades tenham sido concluídas. Se uma atividade, como uma atividade em atraso, estiver nessa zona sem persistência e levar o fluxo de trabalho para o estado ocioso, o fluxo de trabalho não persiste mesmo que o host esteja configurado para manter os fluxos de trabalho quando ociosos. Se uma atividade, como uma atividade persistente, tentar persistir explicitamente na zona sem persistência, uma exceção fatal é gerada, o fluxo de trabalho anulado e FaultException retorna 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 retorna ao chamador, mas pode ser observada se o rastreamento for habilitado. A mensagem para FaultException que retornou ao chamador é "A operação não pôde ser executada porque WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' foi concluída".

Para obter mais informações sobre a correlação solicitação-resposta, consulte Solicitação/Resposta.

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 uma parte dos 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 ordem para rotear mensagens para a instância de fluxo de trabalho correta. Esta seção descreve vários problemas comuns que podem ocorrer ao usar a correlação baseada em conteúdo.

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

Os dados usados para identificar a instância são colocados em hash em uma chave de correlação. Deve-se tomar cuidado para garantir que os dados usados para correlação são exclusivos ou outras colisões na chave de hash podem ocorrer e as mensagens sejam mal roteadas. Por exemplo, uma correlação baseada apenas no nome do 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 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 um código hash. Se a persistência estiver sendo usada, verifique se os dados de identificação atuais não foram usados por uma instância persistente anterior. Desabilitar temporariamente a persistência pode ajudar a identificar esse problema. O rastreamento do 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 que é realmente inicializada, na 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 com TransactedReceiveScope.

Problemas de consulta de correlação

As 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 forem enviadas mesmo que pareça tudo 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 função string. No exemplo a seguir, um MessageQuerySet é configurado para usar um valor literal de 11445 para OrderId e a consulta XPath é comentada.

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

Se uma consulta XPath for configurada incorretamente de forma que nenhum dado de correlação seja recuperado, há o retorno de uma falha com a seguinte mensagem: "Uma consulta de correlação gerou 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 pode ocorrer se você usa o construtor de consultas XPath nas caixas de diálogo Adicionar inicializadores de correlação ou Definição de CorrelatesOn e seu serviço de fluxo de trabalho usa 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 atividade Receive em um fluxo de trabalho. O CartId no cabeçalho da mensagem é usado para correlacionar a mensagem à instância correta. Se a consulta XPath que recupera CartId é criada com as caixas de diálogo de correlação no designer de fluxo de trabalho, gera a consulta XPath incorreta a seguir.

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

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

sm:header()/tempuri:CartId

Essa questão pode ser confirmada 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 atividade Receive configurada para uma operação AddItem 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>