以內容為主
本主題僅適用於 Windows Workflow Foundation 4。
工作流程服務與用戶端及其他服務通訊時,交換的訊息中通常會含有能夠將訊息透過唯一方式關聯特定執行個體的資料。 以內容為主的相互關聯會利用訊息中的此項資料 (例如客戶編號或訂單 ID),將訊息路由至適當的工作流程執行個體。 本主題說明如何在工作流程中使用以內容為主的相互關聯。
使用以內容為主的相互關聯
當工作流程服務具有多個透過單一用戶端存取的方法,以及交換的訊息中有一個資料片段能夠識別所需的執行個體時,就會使用以內容為主的相互關聯。
注意: |
---|
若因繫結不是可支援的內容交換繫結其中一個,而無法使用內容相互關聯時,以內容為主的相互關聯就非常有用。如需詳細資訊內容相互關聯的詳細資訊,請參閱內容交換。 |
這些通訊中使用的每個傳訊活動,都必須在能夠唯一識別該執行個體的訊息中指定資料的位置。 若要進行這項操作,請使用 QueryCorrelationInitializer 或 CorrelatesOn 提供 MessageQuerySet (會在訊息中查詢能夠唯一識別該執行個體的資料)。
注意: |
---|
用於識別執行個體的資料會雜湊成為相互關聯索引鍵。 請特別小心確認用於關聯的資料是否為唯一的資料,否則雜湊索引鍵中可能會發生衝突,導致訊息路由錯誤。 例如,只以客戶名稱為主的相互關聯可能會造成衝突,因為可能會有多位客戶具有相同的名稱。 相互關聯資訊的資料中不可包含冒號 (:),因為冒號已用於分隔訊息查詢的索引鍵和值,以形成後續雜湊的字串。 |
在下列範例中,工作流程服務初始的 Receive/SendReply 會傳回 OrderId
,接著用戶端會在呼叫工作流程服務中的下列 Receive 活動時將它傳回。
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.
上述範例示範以內容為主的相互關聯,這個相互關聯是由 SendReply 所初始化。 MessageQuerySet 會將用於讓這個服務識別後續訊息的資料指定為 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")
}
}
}
}
};
在工作流程中,SendReply 之後的 Receive 活動會接在 SendReply 所初始化的相互關聯之後。 兩個活動共用同一個 CorrelationHandle,但各自擁有其 MessageQuerySet 和 XPathMessageQuery (指定識別資料在該特定訊息中的位置)。 在初始化相互關聯的活動上,這個 MessageQuerySet 是在 CorrelationInitializers 屬性中指定的,而在接下來的任何 Receive 活動中,則是使用 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) } })
};
當資料隨著訊息流動時,以內容為主的相互關聯可由任何傳訊活動 (Send、Receive、SendReply、ReceiveReply) 初始化。 如果特定的資料片段並未隨著訊息流動,則可利用 InitializeCorrelation 活動加以明確初始化。 如果有多個資料片段需要唯一識別該訊息,則可以將多個查詢加入至 MessageQuerySet。 這些範例將CorrelationHandle 明確提供給使用 CorrelatesWith 或 CorrelationHandle 屬性的每個活動,但如果整個工作流程如果只需一個相互關聯 (例如在這個範例中,一切都在 OrderId
上相互關聯),那麼只需使用 WorkflowServiceHost 所提供的隱含相互關聯控制代碼管理即可。
使用 InitializeCorrelation 活動
在上述範例中,OrderId
會透過 SendReply 活動流動至呼叫端,而這就是相互關聯初始化之處。 使用 InitializeCorrelation 活動也能達到同樣的行為。 InitializeCorrelation 活動會採用 CorrelationHandle 及項目字典 (其中的項目代表用於將訊息對應至正確執行個體的資料)。 若要在上述範例中使用 InitializeCorrelation 活動,請移除 SendReply 活動中的 CorrelationInitializers,並且使用 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...
接著,在工作流程中,InitializeCorrelation 活動會在保存填入之資料的變數後以及 Receive 活動 (與初始化的 CorrelationHandle 相互關聯) 前使用。
// 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
}
};
使用工作流程設計工具設定 XPath 查詢
在上述範例中,訊息查詢中使用的活動和 XPath 查詢會在程式碼中指定。 Visual Studio 2010 中的工作流程設計工具也提供從 DataContract 型別產生 XPath 的功能,可用於以內容為主的相互關聯。 上述範例中設定的第一個 XPath 是針對 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")
}
}
}
}
};
若要在工作流程設計工具中設定傳訊活動的 XPath,請在工作流程設計工具中選取該活動。 如果該活動正在初始化相互關聯,如上述範例所示,請按一下省略符號按鈕,顯示 [屬性] 視窗中的 [CorrelationInitializers] 屬性。 [加入相互關聯初始設定式] 對話方塊視窗會隨即顯示。 在這個對話方塊中,您可以指定相互關聯類型,並且選取用於相互關聯的內容。 CorrelationHandle 變數是在 [新增初始設定式] 方塊中指定,而相互關聯型別和相互關聯所使用的資料是從對話方塊的 [XPath 查詢] 區段選取。
上述範例中的第二個 XPath 查詢是在 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) } })
};
若要為不初始化相互關聯的傳訊活動設定 XPath 查詢,請在工作流程設計工具中選取該活動,然後按一下省略符號按鈕,顯示 [屬性] 視窗中的 [CorrelatesOn] 屬性。 [CorrelatesOn 定義] 對話方塊視窗會隨即顯示。
在這個對話中,您可以指定 CorrelationHandle,並且在 [XPath 查詢] 清單中選擇用於建置 XPath 查詢的項目。