コンテンツ ベース
このトピックの内容は、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 に追加できます。これらの例では、CorrelatesWith または CorrelationHandle プロパティを使用して、CorrelationHandle が各アクティビティに明示的に提供されていますが、すべてが OrderId
で相関するこの例のように、ワークフロー全体で必要な関連付けが 1 つのみである場合は、WorkflowServiceHost で提供される、暗黙の関連付けハンドル管理で十分です。
InitializeCorrelation アクティビティの使用
前の例では、SendReply アクティビティを通じて、OrderId
が呼び出し元に送信され、このアクティビティで関連付けが初期化されました。同じ動作を、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 アクティビティは、データを保持する変数が挿入された後、かつ、初期化された CorrelationHandle との関連付けを行う Receive アクティビティの前にワークフローで使用されます。
// 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 のワークフロー デザイナーでは、XPath の生成を、コンテンツ ベースの相関関係の DataContract 型から行うための機能も提供されています。前の例に示した 1 つ目の 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 クエリ] セクションで選択します。
前の例に示した 2 つ目の 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 クエリをビルドします。