Résolution des problèmes de corrélation

La corrélation est utilisée pour lier les messages de service de flux de travail entre eux et à l’instance de flux de travail correcte, mais s’il n’est pas configuré correctement, les messages ne sont pas reçus et les applications ne fonctionnent pas correctement. Cette rubrique fournit une vue d’ensemble de plusieurs méthodes pour résoudre les problèmes de corrélation et répertorie également certains problèmes courants qui peuvent se produire lorsque vous utilisez la corrélation.

Gérer l’événement UnknownMessageReceived

L’événement UnknownMessageReceived se produit lorsqu’un message inconnu est reçu par un service, y compris les messages qui ne peuvent pas être corrélés à une instance existante. Pour les services auto-hébergés, cet événement peut être géré dans l’application hôte.

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

Pour les services hébergés sur le web, cet événement peut être géré en dérivant une classe de WorkflowServiceHostFactory et en substituant 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;
    }
}

Cette valeur personnalisée WorkflowServiceHostFactory peut ensuite être spécifiée dans le svc fichier du service.

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

Lorsque ce gestionnaire est appelé, le message peut être récupéré à l'aide de la propriété Message de UnknownMessageReceivedEventArgs, et il ressemblera à ce qui suit.

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

L’inspection des messages distribués au UnknownMessageReceived gestionnaire peut fournir des indices sur la raison pour laquelle le message n’a pas été corrélé à une instance du service de flux de travail.

Utiliser le suivi pour surveiller la progression du flux de travail

Le suivi permet de surveiller la progression d’un flux de travail. Par défaut, les enregistrements de suivi sont émis pour les événements du cycle de vie du flux de travail, les événements du cycle de vie des activités, la propagation des erreurs et la reprise des signets. En outre, les enregistrements de suivi personnalisés peuvent être émis par des activités personnalisées. Lors de la résolution des problèmes de corrélation, les enregistrements de suivi des activités, les enregistrements de reprise de signet et les enregistrements de propagation d’erreur sont les plus utiles. Les enregistrements de suivi des activités peuvent être utilisés pour déterminer la progression actuelle du flux de travail et vous aider à identifier l’activité de messagerie qui attend actuellement des messages. Les enregistrements de reprise des signets sont utiles, car ils indiquent qu’un message a été reçu par le flux de travail et que les enregistrements de propagation des erreurs fournissent un enregistrement de toutes les erreurs dans le flux de travail. Pour activer le suivi, spécifiez la valeur souhaitée de TrackingParticipant dans le WorkflowExtensionsWorkflowServiceHost. Dans l’exemple suivant, l’exemple ConsoleTrackingParticipant (à partir de l’exemple Custom Tracking ) est configuré à l’aide du profil de suivi par défaut.

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

Un participant de suivi tel que ConsoleTrackingParticipant est utile pour les services de flux de travail auto-hébergés qui ont une fenêtre de console. Pour un service hébergé sur le web, un participant de suivi qui enregistre les informations de suivi dans un magasin durable doit être utilisé, tel que le participant intégré EtwTrackingParticipantou un participant de suivi personnalisé qui enregistre les informations dans un fichier.

Pour plus d’informations sur le suivi et la configuration du suivi pour un service de flux de travail hébergé sur le web, consultez Suivi et traçage des flux de travail, Configuration du suivi pour un flux de travail et les exemples de Suivi [exemples WF].

Utiliser le suivi WCF

Le suivi WCF fournit le suivi du flux de messages vers et depuis un service de flux de travail. Ces informations de suivi sont utiles pour résoudre les problèmes de corrélation, en particulier pour la corrélation basée sur le contenu. Pour activer le suivi, spécifiez les écouteurs de trace souhaités dans la system.diagnostics section du web.config fichier si le service de flux de travail est hébergé sur le web ou si app.config le service de flux de travail est auto-hébergé. Pour inclure le contenu des messages dans le fichier de trace, spécifiez true pour logEntireMessage dans l'élément messageLogging dans la section diagnostics de system.serviceModel. Dans l’exemple suivant, les informations de suivi, y compris le contenu des messages, sont configurées pour être écrites dans un fichier nommé 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>

Pour afficher les informations de trace contenues dans service.svclog, l’outil Visionneuse de trace de service (SvcTraceViewer.exe) est utilisé. Cela est particulièrement utile lors de la résolution des problèmes de corrélation basés sur le contenu, car vous pouvez afficher le contenu du message et voir exactement ce qui est passé et s’il correspond à la corrélation basée sur le CorrelationQuery contenu. Pour plus d’informations sur le suivi WCF, consultez Service Trace Viewer Tool (SvcTraceViewer.exe), Configuration du suivi et utilisation du suivi pour résoudre les problèmes de votre application.

Problèmes courants de corrélation dans l'échange de contextes

Certains types de corrélation nécessitent qu’un type spécifique de liaison soit utilisé pour que la corrélation fonctionne correctement. Les exemples incluent la corrélation de demande-réponse, qui nécessite une liaison bidirectionnelle telle que BasicHttpBinding, et une corrélation d’échange de contexte, qui nécessite une liaison basée sur le contexte telle que BasicHttpContextBinding. La plupart des liaisons prennent en charge les opérations bidirectionnelles afin qu’il ne s’agit pas d’un problème courant pour la corrélation de demande-réponse, mais il n’existe qu’une poignée de liaisons basées sur le contexte, notamment BasicHttpContextBinding, WSHttpContextBindinget NetTcpContextBinding. Si l'une de ces liaisons n'est pas utilisée, l'appel initial à un service de flux de travail réussira, mais les appels suivants échoueront avec le message suivant 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.

Les informations de contexte utilisées pour la corrélation de contexte peuvent être retournées par l’activité SendReplyReceive qui initialise la corrélation de contexte lors de l’utilisation d’une opération bidirectionnelle, ou elle peut être spécifiée par l’appelant si l’opération est unidirectionnelle. Si le contexte n’est pas envoyé par l’appelant ou retourné par le service de flux de travail, le même FaultException décrit précédemment est retourné lorsqu’une opération ultérieure est appelée.

Problèmes courants de corrélation des requêtes-réponses

La corrélation de demande-réponse est utilisée avec une Receive/SendReply paire pour implémenter une opération bidirectionnelle dans un service de flux de travail et avec une Send/ReceiveReply paire qui appelle une opération bidirectionnelle dans un autre service Web. Lors de l’appel d’une opération bidirectionnelle dans un service WCF, le service peut être un service WCF traditionnel basé sur du code impératif ou un service de flux de travail. Pour utiliser la corrélation demande-réponse, une liaison bidirectionnelle doit être utilisée, par BasicHttpBindingexemple, et les opérations doivent être bidirectionnelles.

Si le service de flux de travail dispose d’opérations bidirectionnelles en parallèle, ou de chevauchements Receive/SendReply ou Send/ReceiveReply de paires, la gestion implicite du handle de corrélation fournie par WorkflowServiceHost peut ne pas suffire, en particulier dans les scénarios à forte contrainte, et les messages peuvent ne pas être correctement routés. Pour empêcher ce problème de se produire, nous vous recommandons de toujours spécifier explicitement un CorrelationHandle moment où vous utilisez la corrélation de demande-réponse. Lorsque vous utilisez les modèles SendAndReceiveReply et ReceiveAndSendReply de la section Messagerie de la boîte à outils dans le concepteur de flux de travail, une CorrelationHandle configuration explicite est configurée par défaut. Lors de la construction d’un flux de travail à l’aide du code, le CorrelationHandle est spécifié dans le contexte de la CorrelationInitializers de la première activité de la paire. Dans l’exemple suivant, une Receive activité est configurée avec un élément explicite CorrelationHandle spécifié dans le 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.

La persistance n’est pas autorisée entre une Receive/SendReply paire ou une Send/ReceiveReply paire. Une zone non persistante est créée jusqu'à l'achèvement des deux activités. Si une activité, telle qu’une activité de retard, se trouve dans cette zone sans persistance et provoque l’inactivité du flux de travail, le flux de travail n’est pas conservé même si l’hôte est configuré pour conserver les flux de travail lorsqu’il devient inactif. Si une activité, telle qu'une activité de persistance, tente de persister explicitement dans la zone sans persistance, une exception irrécupérable est levée, le flux de travail est abandonné, et un FaultException est retourné à l'appelant. Le message d’exception irrécupérable est « System.InvalidOperationException : les activités de persistance ne peuvent pas être contenues dans aucun bloc de persistance ». Cette exception n’est pas retournée à l’appelant, mais peut être observée si le suivi est activé. Le message retourné pour FaultException à l'appelant est « Impossible d’effectuer l’opération car WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' a terminé ».

Pour plus d’informations sur la corrélation de demande-réponse, consultez Demande-Réponse.

Problèmes courants de corrélation de contenu

La corrélation basée sur le contenu est utilisée lorsqu’un service de flux de travail reçoit plusieurs messages et qu’un élément de données dans les messages échangés identifie l’instance souhaitée. La corrélation basée sur le contenu utilise ces données dans le message, telles qu’un numéro de client ou un ID de commande, pour acheminer les messages vers l’instance de flux de travail appropriée. Cette section décrit plusieurs problèmes courants qui peuvent se produire lors de l’utilisation de la corrélation basée sur le contenu.

Vérifier que les données d’identification sont uniques

Les données utilisées pour identifier l’instance sont hachées dans une clé de corrélation. Vous devez veiller à ce que les données utilisées pour la corrélation soient uniques, sinon des collisions dans la clé hachée pourraient se produire et entraîner un mauvais routage des messages. Par exemple, une corrélation basée uniquement sur un nom de client peut provoquer une collision, car il peut y avoir plusieurs clients qui ont le même nom. Le signe deux-points (:) ne doit pas être utilisé dans le cadre des données utilisées pour mettre en corrélation le message, car il est déjà utilisé pour délimiter la clé et la valeur de la requête de message pour former la chaîne qui est ensuite hachée. Si la persistance est utilisée, assurez-vous que les données d’identification actuelles n’ont pas été utilisées par une instance précédemment persistante. La désactivation temporaire de la persistance peut vous aider à identifier ce problème. Le suivi WCF peut être utilisé pour afficher la clé de corrélation calculée et est utile pour déboguer ce type de problème.

Conditions de course

Il existe un petit intervalle de temps entre le service recevant un message et la corrélation en cours d’initialisation, pendant laquelle les messages de suivi seront ignorés. Si un service de flux de travail initialise la corrélation basée sur le contenu à l’aide de données transmises par le client via une opération unidirectionnelle et que l’appelant envoie des messages de suivi immédiats, ces messages sont ignorés pendant cet intervalle. Cela peut être évité à l’aide d’une opération bidirectionnelle pour initialiser la corrélation, ou à l’aide d’un TransactedReceiveScope.

Problèmes de requête de corrélation

Les requêtes de corrélation sont utilisées pour spécifier les données d’un message utilisées pour mettre en corrélation le message. Ces données sont spécifiées à l’aide d’une requête XPath. Si les messages à un service ne sont pas distribués même si tout semble correct, une stratégie de résolution des problèmes consiste à spécifier une valeur littérale qui correspond à la valeur des données de message au lieu d’une requête XPath. Pour spécifier une valeur littérale, utilisez la string fonction. Dans l'exemple suivant, un paramètre MessageQuerySet est configuré pour utiliser une valeur littérale de 11445, et la requête XPath OrderId est commentée.

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

Si une requête XPath est configurée de manière incorrecte, de sorte qu’aucune donnée de corrélation n’est récupérée, une erreur est retournée avec le message suivant : « Une requête de corrélation a généré un jeu de résultats vide. Vérifiez que les requêtes de corrélation pour le point de terminaison sont correctement configurées. » Un moyen rapide de résoudre ce problème consiste à remplacer la requête XPath par une valeur littérale, comme décrit dans la section précédente. Ce problème peut se produire si vous utilisez le générateur de requêtes XPath dans boîtes de dialogue Ajouter des initialiseurs de corrélation ou Définition CorrelatesOn et si votre service de flux de travail utilise des contrats de message. Dans l’exemple suivant, une classe de contrat de message est définie.

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

    [MessageBodyMember]
    public string Item;
}

Ce contrat de message est utilisé par une Receive activité dans un flux de travail. L’en-tête CartId du message est utilisé pour mettre en corrélation le message à l’instance correcte. Si la requête XPath qui récupère l’objet CartId est créée à l’aide des boîtes de dialogue de corrélation dans le concepteur de flux de travail, la requête XPath incorrecte suivante est générée.

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

Cette requête XPath serait correcte si l’activité Receive utilisait des paramètres pour les données, mais étant donné qu'elle utilise un contrat de message, elle est incorrecte. La requête XPath suivante est la bonne requête XPath pour récupérer CartId depuis l’en-tête.

sm:header()/tempuri:CartId

Cela peut être confirmé en examinant le corps du message.

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

L’exemple suivant montre une Receive activité configurée pour une AddItem opération qui utilise le contrat de message précédent pour recevoir des données. La requête XPath est correctement configurée.

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