Basé sur le contenu

Cette rubrique s'applique à Windows Workflow Foundation 4.

Lorsque les services de workflow communiquent avec des clients et d'autres services, il existe souvent des données dans les messages échangés qui servent uniquement à lier un message à une instance particulière. La corrélation basée sur le contenu utilise ces données dans les messages, par exemple un numéro de client ou un ID de commande, pour router les messages vers l'instance de workflow appropriée. Cette rubrique explique comment utiliser la corrélation basée sur le contenu dans les workflows.

Utilisation de la corrélation basée sur le contenu

La corrélation basée sur le contenu est utilisée lorsqu'un service de workflow possède plusieurs méthodes accessibles par un client unique et dispose de quelques données dans les messages échangés qui identifient l'instance souhaitée.

Ee358755.note(fr-fr,VS.100).gifRemarque :
La corrélation basée sur le contenu est utile lorsque la corrélation de contexte ne peut pas être utilisée parce que la liaison ne fait pas partie des liaisons d'échange de contexte compatibles. Pour plus d'informations sur le sujet suivant la corrélation de contexte, consultez Échange de contexte.

Chaque activité de messagerie utilisée dans ce type de communication doit spécifier à quel emplacement dans le message se trouvent les données identifiant l'instance de manière unique. Cela s'effectue en fournissant un objet MessageQuerySet, utilisant un objet QueryCorrelationInitializer ou une propriété CorrelatesOn, qui recherche dans le message les données identifiant l'instance de manière unique.

Ee358755.Warning(fr-fr,VS.100).gif Attention :
Les données utilisées pour identifier l'instance sont hachées en une clé de corrélation. Il est important de s'assurer que les données utilisées pour la corrélation sont uniques, pour éviter que des conflits se produisent dans la clé hachée, entraînant des confusions dans le routage des messages. Par exemple, une corrélation basée uniquement sur un nom de client risque de provoquer un conflit, au cas où d'autres clients aient un nom identique. Les deux-points (:) ne doivent pas être utilisés à l'intérieur des données qui servent à mettre les messages en corrélation. En effet, ils servent déjà à délimiter la clé et la valeur de la requête de message pour former la chaîne qui est ensuite hachée.

Dans l'exemple suivant, la paire d'activités initiale Receive/SendReply d'un service de workflow retourne un OrderId, qui est ensuite retransmis par le client lors du prochain appel à l'activité Receive dans le service de workflow.

Variable<string> OrderId = new Variable<string>();
Variable<string> Item = new Variable<string>();
Variable<CorrelationHandle> OrderIdHandle = new Variable<CorrelationHandle>();

Receive StartOrder = new Receive
{
    CanCreateInstance = true,
    ServiceContractName = "IOrderService",
    OperationName = "StartOrder"
};

SendReply ReplyToStartOrder = new SendReply
{
    Request = StartOrder,
    Content = SendParametersContent.Create(new Dictionary<string, InArgument>
        { { "OrderId", new InArgument<string>((env) => OrderId.Get(env)) } }),
    CorrelationInitializers =
    {
        new QueryCorrelationInitializer
        {
            CorrelationHandle = OrderIdHandle,
            MessageQuerySet = new MessageQuerySet
            {
                {
                    "OrderId", 
                    new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
                }
            }
        }
    }
};

Receive AddItem = new Receive
{
    ServiceContractName = "IOrderService",
    OperationName = "AddItem",
    CorrelatesWith = OrderIdHandle,
    CorrelatesOn = new MessageQuerySet
    {
        {
            "OrderId", 
              new XPathMessageQuery("sm:body()/tempuri:AddItem/tempuri:OrderId")
        }
    },
    Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>
        { { "OrderId", new OutArgument<string>(OrderId) },  
        { "Item", new OutArgument<string>(Item) } })
};

SendReply ReplyToAddItem = new SendReply
{
    Request = AddItem,
    Content = SendParametersContent.Create(new Dictionary<string, InArgument>
        { { "Reply", new InArgument<string>((env) => "Item added: " + Item.Get(env)) } }),
};

// Construct a workflow using StartOrder, ReplyToStartOrder, and AddItem.

L'exemple précédent montre une corrélation basée sur le contenu initialisée par l'activité SendReply. L'objet MessageQuerySet spécifie que les données utilisées pour identifier les prochains messages vers ce service correspondent à OrderId.

SendReply ReplyToStartOrder = new SendReply
{
    Request = StartOrder,
    Content = SendParametersContent.Create(new Dictionary<string, InArgument>
        { { "OrderId", new InArgument<string>((env) => OrderId.Get(env)) } }),
    CorrelationInitializers =
    {
        new QueryCorrelationInitializer
        {
            CorrelationHandle = OrderIdHandle,
            MessageQuerySet = new MessageQuerySet
            {
                {
                    "OrderId", 
                    new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
                }
            }
        }
    }
};

L'activité Receive qui succède à l'activité SendReply dans le workflow respecte la corrélation initialisée par l'activité SendReply. Les deux activités partagent le même CorrelationHandle, mais chacune possède son propre MessageQuerySet et son propre XPathMessageQuery qui spécifie où se trouvent les données d'identification dans ce message particulier. Pour l'activité qui initialise la corrélation, ce MessageQuerySet est spécifié dans la propriété CorrelationInitializers, et pour toutes les activités Receive qui lui succèdent, il est spécifié à l'aide de la propriété CorrelatesOn.

Receive AddItem = new Receive
{
    ServiceContractName = "IOrderService",
    OperationName = "AddItem",
    CorrelatesWith = OrderIdHandle,
    CorrelatesOn = new MessageQuerySet
    {
        {
            "OrderId", 
              new XPathMessageQuery("sm:body()/tempuri:AddItem/tempuri:OrderId")
        }
    },
    Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>
        { { "OrderId", new OutArgument<string>(OrderId) },  
        { "Item", new OutArgument<string>(Item) } })
};

Une corrélation basée sur le contenu peut être initialisée par n'importe quelle activité de messagerie (Send, Receive, SendReply, ReceiveReply) lorsque les données circulent dans le cadre d'un message. Si ces données particulières ne circulent pas dans le cadre d'un message, la corrélation peut alors être initialisée de manière explicite à l'aide de l'activité InitializeCorrelation. Si plusieurs fragments de données sont nécessaires pour identifier le message de manière unique, plusieurs requêtes peuvent être ajoutées au MessageQuerySet. Dans ces exemples, un objet CorrelationHandle a été fourni de manière explicite à chacune des activités à l'aide des propriétés CorrelatesWith ou CorrelationHandle, mais si une seule corrélation est nécessaire pour l'intégralité du workflow, comme dans cet exemple où tout est mis en corrélation en fonction d'OrderId, la gestion de handle de corrélation implicite fournie par WorkflowServiceHost suffit.

Utilisation de l'activité InitializeCorrelation

Dans l'exemple précédent, l'OrderId était transmis à l'appelant via l'activité SendReply, celle qui a initialisé la corrélation. Le même comportement peut être obtenu à l'aide de l'activité InitializeCorrelation. L'activité InitializeCorrelation prend le CorrelationHandle et un dictionnaire d'éléments qui représentent les données utilisées pour mapper le message à l'instance correcte. Pour utiliser l'activité InitializeCorrelation dans l'exemple précédent, supprimez la propriété CorrelationInitializers de l'activité SendReply et initialisez la corrélation à l'aide de l'activité InitializeCorrelation.

Variable<string> OrderId = new Variable<string>();
Variable<string> Item = new Variable<string>();
Variable<CorrelationHandle> OrderIdHandle = new Variable<CorrelationHandle>();

InitializeCorrelation OrderIdCorrelation = new InitializeCorrelation
{
    Correlation = OrderIdHandle,
    CorrelationData = { { "OrderId", new InArgument<string>(OrderId) } }
};

Receive StartOrder = new Receive
{
    CanCreateInstance = true,
    ServiceContractName = "IOrderService",
    OperationName = "StartOrder"
};

SendReply ReplyToStartOrder = new SendReply
{
    Request = StartOrder,
    Content = SendParametersContent.Create(new Dictionary<string, InArgument> { { "OrderId", new InArgument<string>((env) => OrderId.Get(env)) } }),
};

// Other messaging activities omitted...

L'activité InitializeCorrelation est alors utilisée dans le workflow, une fois remplies les variables qui contiennent les données, mais avant l'activité Receive qui se met en corrélation avec l'objet CorrelationHandle initialisé.

// Construct a workflow using OrderIdCorrelation, StartOrder, ReplyToStartOrder,
// and other messaging activities.
Activity wf = new Sequence
{
    Variables =
    {
        OrderId,
        Item,
        OrderIdHandle
    },
    Activities =
    {
        // Wait for a new order.
        StartOrder,
        // Assign a unique identifier to the order.
        new Assign<string>
        {
            To = new OutArgument<string>( (env) => OrderId.Get(env)),
            Value = new InArgument<string>( (env) => Guid.NewGuid().ToString() )
        },
        ReplyToStartOrder,
        // Initialize the correlation.
        OrderIdCorrelation,
        // Wait for an item to be added to the order.
        AddItem,
        ReplyToAddItem
     }
};

Configuration de requêtes XPath à l'aide du Workflow Designer

Dans les exemples précédents, les activités et les requêtes XPath utilisées dans les requêtes de message ont été spécifiées dans le code. Le Workflow Designer de Visual Studio 2010 fournit également la possibilité de générer des XPaths à partir de types DataContract pour la corrélation basée sur le contenu. Le premier XPath configuré dans l'exemple précédent a été configuré pour l'activité SendReply.

SendReply ReplyToStartOrder = new SendReply
{
    Request = StartOrder,
    Content = SendParametersContent.Create(new Dictionary<string, InArgument>
        { { "OrderId", new InArgument<string>((env) => OrderId.Get(env)) } }),
    CorrelationInitializers =
    {
        new QueryCorrelationInitializer
        {
            CorrelationHandle = OrderIdHandle,
            MessageQuerySet = new MessageQuerySet
            {
                {
                    "OrderId", 
                    new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
                }
            }
        }
    }
};

Sélectionnez l'activité de messagerie pour laquelle vous souhaitez configurer le XPath dans le Workflow Designer. Si l'activité initialise la corrélation, comme dans l'exemple précédent, cliquez sur le bouton de sélection de la propriété CorrelationInitializers dans la fenêtre Propriétés. La boîte de dialogue Ajouter des initialiseurs de corrélation s'affiche. Dans cette fenêtre, vous pouvez spécifier le type de corrélation et sélectionner le contenu utilisé pour la corrélation. La spécification de la variable CorrelationHandle s'effectue dans la zone Ajouter un initialiseur. La sélection du type de corrélation et des données à utiliser s'effectue dans la section Requêtes XPath de la boîte de dialogue.

Boîte de dialogue CorrelationInitializer

La deuxième requête XPath de l'exemple précédent a été configurée dans l'activité Receive.

Receive AddItem = new Receive
{
    ServiceContractName = "IOrderService",
    OperationName = "AddItem",
    CorrelatesWith = OrderIdHandle,
    CorrelatesOn = new MessageQuerySet
    {
        {
            "OrderId", 
              new XPathMessageQuery("sm:body()/tempuri:AddItem/tempuri:OrderId")
        }
    },
    Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>
        { { "OrderId", new OutArgument<string>(OrderId) },  
        { "Item", new OutArgument<string>(Item) } })
};

Pour configurer la requête XPath pour une activité de messagerie qui n'initialise pas la corrélation, sélectionnez l'activité dans le Workflow Designer puis cliquez sur le bouton de sélection de la propriété CorrelatesOn dans la fenêtre Propriétés. La boîte de dialogue Définition CorrelatesOn s'affiche.

Définition de CorrelatesOn

Dans cette fenêtre, spécifiez l'objet CorrelationHandle et choisissez des éléments dans la liste Requêtes XPath pour générer la requête XPath.