Comparteix a través de


Solución de problemas de correlación

La correlación se usa para relacionar los mensajes del servicio de flujo de trabajo entre sí y con la instancia de flujo de trabajo correcta, pero si no está configurado correctamente, los mensajes no se recibirán y las aplicaciones no funcionarán correctamente. En este tema se proporciona información general sobre varios métodos para solucionar problemas de correlación y también se enumeran algunos problemas comunes que pueden producirse al usar la correlación.

Controlar el evento UnknownMessageReceived

El UnknownMessageReceived evento se produce cuando un servicio recibe un mensaje desconocido, incluidos los mensajes que no se pueden correlacionar con una instancia existente. En el caso de los servicios autohospedados, este evento se puede controlar en la aplicación host.

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

En el caso de los servicios hospedados en web, este evento se puede controlar derivando una clase de WorkflowServiceHostFactory y reemplazando 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;
    }
}

A continuación, este WorkflowServiceHostFactory personalizado se puede especificar en el archivo svc del servicio.

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

Cuando se invoca este controlador, el mensaje se puede recuperar mediante la Message propiedad de UnknownMessageReceivedEventArgsy será similar al siguiente mensaje.

<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>

Inspeccionar los mensajes enviados al UnknownMessageReceived controlador puede proporcionar pistas sobre por qué el mensaje no se correlacionaba con una instancia del servicio de flujo de trabajo.

Uso del seguimiento para supervisar el progreso del flujo de trabajo

El seguimiento proporciona una manera de supervisar el progreso de un flujo de trabajo. De forma predeterminada, los registros de seguimiento se emiten para los eventos del ciclo de vida del flujo de trabajo, los eventos del ciclo de vida de la actividad, la propagación de errores y la reanudación de marcadores. Además, las actividades personalizadas pueden emitir registros de seguimiento personalizados. Al solucionar problemas de correlación, los registros de seguimiento de actividad, los registros de reanudación del marcador y los registros de propagación de errores son los más útiles. Los registros de seguimiento de actividad se pueden usar para determinar el progreso actual del flujo de trabajo y pueden ayudar a identificar qué actividad de mensajería está esperando actualmente los mensajes. Los registros de reanudación de marcadores son útiles porque indican que el flujo de trabajo recibió un mensaje y los registros de propagación de errores proporcionan un registro de los errores del flujo de trabajo. Para habilitar el seguimiento, especifique el TrackingParticipant deseado en el WorkflowExtensions del WorkflowServiceHost. En el siguiente ejemplo, el ConsoleTrackingParticipant (del ejemplo de seguimiento personalizado) se configura mediante el perfil de seguimiento predeterminado.

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

Un participante de seguimiento como ConsoleTrackingParticipant es útil para los servicios de flujo de trabajo autohospedados que tienen una ventana de consola. Para un servicio hospedado en web, se debe usar un participante de seguimiento que registra la información de seguimiento en un almacén duradero, como el participante integrado EtwTrackingParticipanto un participante de seguimiento personalizado que registra la información en un archivo.

Para obtener más información sobre el seguimiento y la configuración del seguimiento de un servicio de flujo de trabajo hospedado en web, consulte Seguimiento y trazado de flujos de trabajo, Configuración del seguimiento de un flujo de trabajo y los ejemplos Seguimiento [ejemplos de WF].

Uso del seguimiento de WCF

El rastreo de WCF proporciona seguimiento del flujo de mensajes hacia y desde un servicio de flujo de trabajo. Esta información de seguimiento es útil al solucionar problemas de correlación, especialmente para la correlación basada en contenido. Para habilitar el seguimiento, especifique los agentes de escucha de seguimiento deseados en la sección system.diagnostics del archivo si el servicio de flujo de trabajo está hospedado en la web, o en el archivo app.config si el servicio de flujo de trabajo está autohospedado. Para incluir el contenido de los mensajes en el archivo de seguimiento, especifique true para logEntireMessage dentro del elemento messageLogging en la sección diagnostics de system.serviceModel. En el ejemplo siguiente, la información de seguimiento, incluido el contenido de los mensajes, está configurada para escribirse en un archivo denominado 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 la información de seguimiento contenida en service.svclog, se usa la herramienta Visor de seguimiento de servicio (SvcTraceViewer.exe). Esto resulta especialmente útil al solucionar problemas de correlación basados en contenido porque puede ver el contenido del mensaje y ver exactamente lo que se pasa y si coincide con el CorrelationQuery para la correlación basada en contenido. Para obtener más información sobre el seguimiento de WCF, vea Herramienta de Visualización de Trazas del Servicio (SvcTraceViewer.exe), Configuración del Seguimiento y Uso del Seguimiento para Solucionar Problemas de su Aplicación.

Problemas comunes de correlación de contexto de Exchange

Ciertos tipos de correlación requieren que se use un tipo específico de enlace para que la correlación funcione correctamente. Entre los ejemplos se incluye la correlación de solicitud-respuesta, que requiere un enlace bidireccional, como BasicHttpBinding, y correlación de intercambio de contexto, que requiere un enlace basado en contexto, como BasicHttpContextBinding. La mayoría de los enlaces admiten operaciones bidireccionales, por lo que no es un problema común para la correlación de solicitud-respuesta, pero solo hay un puñado de enlaces basados en contexto, como BasicHttpContextBinding, WSHttpContextBindingy NetTcpContextBinding. Si no se usa uno de estos enlaces, la llamada inicial a un servicio de flujo de trabajo se realizará correctamente, pero las llamadas posteriores producirán un error con lo siguiente 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.

La información de contexto que se usa para la correlación de contexto se puede devolver por SendReply a la actividad Receive que inicializa la correlación de contexto al usar una operación bidireccional, o bien puede ser especificada por el llamador si la operación es unidireccional. Si el llamador no envía el contexto o el servicio de flujo de trabajo no lo devuelve, se devolverá el mismo FaultException descrito anteriormente cuando se invoque una operación posterior.

Problemas comunes de correlación de Request-Reply

La correlación de solicitud-respuesta se usa con un Receive/SendReply par para implementar una operación bidireccional en un servicio de flujo de trabajo y con un Send/ReceiveReply par que invoca una operación bidireccional en otro servicio web. Al invocar una operación bidireccional en un servicio WCF, el servicio puede ser un servicio WCF basado en código tradicional o puede ser un servicio de flujo de trabajo. Para usar la correlación de solicitud-respuesta, se debe usar un enlace bidireccional, como BasicHttpBinding, y las operaciones deben ser bidireccionales.

Si el servicio de flujo de trabajo tiene operaciones bidireccionales en paralelo o superpuestas Receive/SendReply oSend/ReceiveReplypares, es posible que la administración implícita del controlador de correlación proporcionada por WorkflowServiceHost no sea suficiente, especialmente en escenarios de alto estrés, y es posible que los mensajes no se enruten correctamente. Para evitar que se produzca este problema, se recomienda especificar siempre explícitamente un al usar la CorrelationHandle correlación de solicitud-respuesta. Al utilizar las plantillas SendAndReceiveReply y ReceiveAndSendReply de la sección Mensajería del Cuadro de herramientas en el diseñador de flujos de trabajo, CorrelationHandle se configura explícitamente por defecto. Al construir un flujo de trabajo mediante código, CorrelationHandle se especifica en el CorrelationInitializers de la primera actividad en el par. En el ejemplo siguiente, una Receive actividad se configura con una CorrelationHandle explícita especificada en el 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.

No se permite la persistencia entre un Receive/SendReply par o un Send/ReceiveReply par. Se crea una zona sin persistencia que dura hasta que se hayan completado ambas actividades. Si una actividad, como una actividad de retraso, se encuentra en esta zona sin persistencia y hace que el flujo de trabajo se vuelva inactivo, el flujo de trabajo no se conservará aunque el host esté configurado para conservar los flujos de trabajo cuando se vuelven inactivos. Si una actividad, como una actividad de persistencia, intenta persistir explícitamente en la zona de no persistencia, se produce una excepción irrecuperable, se anula el flujo de trabajo y FaultException se devuelve al autor de la llamada. El mensaje de excepción irrecuperable es "System.InvalidOperationException: Las actividades persistentes no pueden estar dentro de bloques sin persistencia". Esta excepción no se devuelve al autor de la llamada, pero se puede observar si el seguimiento está habilitado. El mensaje del FaultException devuelto al autor de la llamada es "No se pudo realizar la operación porque WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' se ha completado".

Para obtener más información sobre la correlación de solicitud-respuesta, consulte Request-Reply.

Problemas comunes de correlación de contenido

La correlación basada en contenido se usa cuando un servicio de flujo de trabajo recibe varios mensajes y un fragmento de datos en los mensajes intercambiados identifica la instancia deseada. La correlación basada en contenido usa estos datos en el mensaje, como un número de cliente o un identificador de pedido, para enrutar los mensajes a la instancia de flujo de trabajo correcta. En esta sección se describen varios problemas comunes que pueden producirse al usar la correlación basada en contenido.

Asegurarse de que los datos de identificación son únicos

Los datos que se usan para identificar la instancia se convierten en un hash dentro de una clave de correlación. Se debe tener cuidado para garantizar que los datos que se usan para la correlación son únicos o, de lo contrario, pueden producirse colisiones en la clave hash y provocar que los mensajes se enrutan de forma incorrecta. Por ejemplo, una correlación basada solo en un nombre de cliente puede provocar una colisión porque puede haber varios clientes que tengan el mismo nombre. Los dos puntos (:) no deben usarse como parte de los datos que se utilizan para correlacionar el mensaje porque ya se utiliza para delimitar la clave y el valor de la consulta del mensaje para formar la cadena que se cifra posteriormente. Si se usa la persistencia, asegúrese de que una instancia persistente no ha usado los datos de identificación actuales. Deshabilitar temporalmente la persistencia puede ayudar a identificar este problema. El seguimiento de WCF se puede usar para ver la clave de correlación calculada y es útil para depurar este tipo de problema.

Condiciones de carrera

Hay un pequeño intervalo de tiempo entre el servicio que recibe un mensaje y la correlación que se inicializa realmente, durante el cual se omitirán los mensajes de seguimiento. Si un servicio de flujo de trabajo inicializa la correlación basada en contenido mediante datos pasados desde el cliente a través de una operación unidireccional y el autor de la llamada envía mensajes de seguimiento inmediatos, estos mensajes se omitirán durante este intervalo. Esto se puede evitar mediante una operación bidireccional para inicializar la correlación o mediante .TransactedReceiveScope

Problemas de consulta de correlación

Las consultas de correlación se usan para especificar qué datos de un mensaje se usan para correlacionar el mensaje. Estos datos se especifican mediante una consulta XPath. Si los mensajes a un servicio no se envían aunque todo parezca correcto, una estrategia para solucionar problemas es especificar un valor literal que coincida con el valor de los datos del mensaje en lugar de una consulta XPath. Para especificar un valor literal, use la string función . En el ejemplo siguiente, se configura un MessageQuerySet para usar un valor literal de 11445 para OrderId y se comenta la consulta XPath.

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

Si una consulta XPath está configurada incorrectamente de modo que no se recupera ningún dato de correlación, se devuelve un error con el siguiente mensaje: "Una consulta de correlación produjo un conjunto de resultados vacío. Asegúrese de que las consultas de correlación para el punto de conexión están configuradas correctamente". Una manera rápida de solucionar este problema es reemplazar la consulta XPath por un valor literal, como se describe en la sección anterior. Este problema puede producirse si utiliza el generador de consultas XPath en los cuadros de diálogo Agregar inicializadores de correlación o Definición de CorrelatesOn y su servicio de flujo de trabajo emplea contratos de mensajes. En el ejemplo siguiente, se define una clase de contrato de mensaje.

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

    [MessageBodyMember]
    public string Item;
}

Este contrato de mensaje es utilizado por una actividad Receive en un flujo de trabajo. El CartId en el encabezado del mensaje se utiliza para vincular el mensaje con la instancia correcta. Si la consulta XPath que recupera CartId se crea mediante los diálogos de correlación en el diseñador de flujo de trabajo, se genera la siguiente consulta XPath incorrecta.

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

Esta consulta XPath sería correcta si la Receive actividad usaba parámetros para los datos, pero dado que usa un contrato de mensaje, no es correcto. La siguiente consulta XPath es la consulta XPath correcta para recuperar el CartId del encabezado.

sm:header()/tempuri:CartId

Esto se puede confirmar examinando el cuerpo del mensaje.

<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>

En el ejemplo siguiente se muestra una Receive actividad configurada para una AddItem operación que usa el contrato de mensaje anterior para recibir datos. La consulta XPath está configurada correctamente.

<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>