Basado en contenidos
Este tema es aplicable a Windows Workflow Foundation 4.
Cuando los servicios de flujo de trabajo se comunican con clientes y otros servicios, suele haber ciertos datos en los mensajes intercambiados que relacionan de forma única un mensaje con una instancia determinada. La correlación basada en contenidos usa estos datos en el mensaje, como un número de cliente o un identificador de orden, para enrutar los mensajes a la instancia de flujo de trabajo apropiada. En este tema, se explica cómo utilizar la correlación basada en contenidos en flujos de trabajo.
Utilizar la correlación basada en contenidos
Se utiliza la correlación basada en contenidos cuando un servicio de flujo de trabajo tiene varios métodos a los que se accede mediante un cliente único y una parte de los datos de los mensajes intercambiados identifica la instancia deseada.
Nota: |
---|
La correlación basada en contenidos es útil cuando no se puede utilizar la correlación del contexto porque el enlace no es ninguno de los enlaces de intercambio de contexto compatibles. Para obtener más información sobre la correlación de contexto, vea Intercambio de contexto. |
Cada actividad de mensajería utilizada en estas comunicaciones debe especificar la ubicación de los datos del mensaje que identifican de forma única la instancia. Esto se hace proporcionando MessageQuerySet, utilizando QueryCorrelationInitializer o CorrelatesOn, de manera que se envía una consulta al mensaje sobre la parte o las partes de los datos que identifican de forma única la instancia.
Precaución: |
---|
A los datos que se utilizan para identificar la instancia se les aplica un algoritmo hash en una clave de correlación. Preste atención para asegurarse de que los datos utilizados para la correlación son únicos; de otro modo, podrían producirse colisiones en la clave a la que se ha aplicado un algoritmo hash y hacer que los mensajes se envíen a un destino incorrecto. Por ejemplo, una correlación basada solamente en un nombre de cliente puede producir una colisión porque puede haber múltiples clientes con el mismo nombre. Los dos puntos (:) no se deberían utilizar como parte de los datos empleados para la correlación del mensaje, porque ya se utilizan para delimitar el valor y la clave de la consulta del mensaje para formar la cadena a la que, posteriormente, se aplica un algoritmo hash. |
En el siguiente ejemplo, la clase Receive/SendReply inicial de un servicio de flujo de trabajo devuelve OrderId
, que es devuelto a continuación por el cliente en la llamada a la siguiente actividad Receive en el servicio de flujo de trabajo.
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.
En el ejemplo anterior, se muestra una correlación basada en contenidos que se inicializada mediante SendReply. MessageQuerySet especifica que los datos utilizados para identificar los mensajes subsiguientes de este servicio son 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")
}
}
}
}
};
La actividad Receive que sigue a SendReply en el flujo de trabajo continúa la correlación inicializada por SendReply. Ambas actividades comparten la misma clase CorrelationHandle, pero cada una tiene su propia MessageQuerySet y XPathMessageQuery que especifica dónde están los datos de identificación de ese mensaje en particular. En la actividad que inicializa la correlación, MessageQuerySet se especifica en la propiedad CorrelationInitializers y, para cualquier actividad Receive siguiente, se especifica utilizando la propiedad 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) } })
};
Cualquier actividad de mensajería (Send, Receive, SendReply, ReceiveReply) puede inicializar una correlación basada en contenidos cuando los datos se transmiten como parte de un mensaje. Si la parte determinada de los datos no se transmite como parte de un mensaje, entonces se puede inicializar explícitamente utilizando la actividad InitializeCorrelation. Si es necesario que múltiples partes de los datos identifiquen el mensaje de forma única, entonces pueden agregarse múltiples consultas a MessageQuerySet. En estos ejemplos, CorrelationHandle se proporcionó explícitamente a cada una de las actividades utilizando las propiedades CorrelatesWith o CorrelationHandle, pero si solo hay una correlación requerida para el flujo de trabajo completo, como en este ejemplo, donde todo se correlaciona en OrderId
, la administración de identificación de correlación implícita proporcionada por WorkflowServiceHost es suficiente.
Usar la actividad InitializeCorrelation
En el ejemplo anterior, OrderId
se transmitió al autor de la llamada a través de la actividad SendReply, y ahí es donde se inicializó la correlación. E mismo comportamiento se puede lograr utilizando la actividad InitializeCorrelation. La actividad InitializeCorrelation toma CorrelationHandle y un diccionario de elementos que representan los datos utilizados para asignar el mensaje a la instancia correcta. Para utilizar la actividad InitializeCorrelation en el ejemplo anterior, quite CorrelationInitializers de la actividad SendReply e inicialice la correlación mediante la actividad 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...
A continuación, la actividad InitializeCorrelation se utiliza en el flujo de trabajo, una vez rellenadas las variables que contienen los datos, pero antes de la actividad Receive que se correlaciona con la clase CorrelationHandle inicializada.
// 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
}
};
Configurar consultas de XPath utilizando el Diseñador de flujo de trabajo
En los ejemplos anteriores, las actividades y las consultas XPath utilizadas en las consultas del mensaje se especificaron en código. El Diseñador de flujo de trabajo en Visual Studio 2010 también proporciona la capacidad de generar XPaths de los tipos DataContract para la correlación basada en contenidos. El primer XPath configurado en el ejemplo anterior se configuró para 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")
}
}
}
}
};
Para configurar el XPath para una actividad de mensajería en el Diseñador de flujo de trabajo, seleccione la actividad en el Diseñador de flujo de trabajo. Si la actividad inicializa la correlación, como en el ejemplo anterior, haga clic en el botón de puntos suspensivos para acceder a la propiedad CorrelationInitializers en la ventana Propiedades. Esto muestra el recuadro de diálogo Agregar inicializadores de correlación. En este cuadro de diálogo, puede especificar el tipo de correlación y seleccionar el contenido que se usará para ella. La variable CorrelationHandle se especifica en el cuadro Agregar inicializador y el tipo de correlación y datos utilizados para la correlación se seleccionan en la sección Consultas XPath del cuadro de diálogo.
La segunda consulta XPath del ejemplo anterior se configuró en la actividad 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) } })
};
Para configurar la consulta XPath para una actividad de mensajería que no inicializa la correlación, seleccione la actividad en el Diseñador de flujo de trabajo y, a continuación, haga clic en el botón de puntos suspensivos para acceder a la propiedad CorrelatesOn en la ventana Propiedades. Esto muestra el cuadro de diálogo Definición de CorrelatesOn.
En este diálogo, puede especificar CorrelationHandle y seleccionar elementos en la lista Consultas XPath para compilar la consulta XPath.