相関関係は、ワークフロー サービス メッセージを相互に関連付け、正しいワークフロー インスタンスに関連付けるために使用されますが、正しく構成されていない場合、メッセージは受信されず、アプリケーションは正しく機能しません。 このトピックでは、関連付けの問題をトラブルシューティングするためのいくつかの方法の概要と、関連付けの使用時に発生する可能性がある一般的な問題の一覧を示します。
UnknownMessageReceived イベントを処理する
UnknownMessageReceived イベントは、既存のインスタンスに関連付けられないメッセージを含む、不明なメッセージがサービスによって受信されたときに発生します。 セルフホステッド サービスの場合、このイベントはホスト アプリケーションで処理できます。
host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
Console.WriteLine("Unknown Message Received:");
Console.WriteLine(e.Message);
};
Web でホストされるサービスの場合、このイベントは、 WorkflowServiceHostFactory からクラスを派生させ、 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;
}
}
このカスタム WorkflowServiceHostFactory は、サービスの svc ファイルで指定できます。
<% @ServiceHost Language="C#" Service="OrderServiceWorkflow" Factory="CustomFactory" %>
このハンドラーが呼び出されると、Messageの UnknownMessageReceivedEventArgs プロパティを使用してメッセージを取得でき、次のメッセージのようになります。
<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>
UnknownMessageReceived ハンドラーにディスパッチされたメッセージを検査すると、メッセージがワークフロー サービスのインスタンスに関連付けられなかった理由に関する手掛かりが得られます。
追跡を使用してワークフローの進行状況を監視する
追跡は、ワークフローの進行状況を監視する方法を提供します。 既定では、追跡レコードは、ワークフロー ライフサイクル イベント、アクティビティ ライフサイクル イベント、障害伝達、ブックマーク再開に対して出力されます。 さらに、カスタム追跡レコードは、カスタム アクティビティによって出力できます。 相関関係のトラブルシューティングを行うときは、アクティビティ追跡レコード、ブックマーク再開レコード、および障害伝達レコードが最も役立ちます。 アクティビティ追跡レコードを使用して、ワークフローの現在の進行状況を確認できます。また、メッセージを現在待機しているメッセージング アクティビティを特定するのに役立ちます。 ブックマーク再開レコードは、ワークフローによってメッセージが受信されたことを示し、障害伝達レコードはワークフロー内のエラーのレコードを提供するため便利です。 追跡を有効にするには、TrackingParticipantのWorkflowExtensionsで目的のWorkflowServiceHostを指定します。 次の例では、(ConsoleTrackingParticipant サンプルの) は、既定の追跡プロファイルを使用して構成されています。
host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());
ConsoleTrackingParticipant などの追跡参加要素は、コンソール ウィンドウがあるセルフホステッド ワークフロー サービスに役立ちます。 Web ホスト型サービスの場合は、追跡情報を永続ストアに記録する追跡参加要素 (組み込みの EtwTrackingParticipantなど)、または情報をファイルに記録するカスタム追跡参加要素を使用する必要があります。
Web ホスト型ワークフロー サービスの追跡と構成の詳細については、「 ワークフローの追跡とトレース」、ワークフローの 追跡の構成、 および追跡 [WF サンプル] の サンプルを参照してください。
WCF トレースを使用する
WCF トレースは、ワークフロー サービスとの間のメッセージ フローのトレースを提供します。 このトレース情報は、特にコンテンツ ベースの相関関係に関する相関関係の問題をトラブルシューティングする場合に役立ちます。 トレースを有効にするには、ワークフロー サービスが Web ホストの場合はsystem.diagnostics ファイルのweb.config セクションで目的のトレース リスナーを指定し、ワークフロー サービスがセルフホステッドの場合はapp.config ファイルを指定します。 メッセージの内容をトレース ファイルに含めるには、system.serviceModel の diagnostics セクションの messageLogging 要素で、logEntireMessage に true を指定します。 次の例では、メッセージの内容を含むトレース情報が、 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>
service.svclogに含まれるトレース情報を表示するには、サービス トレース ビューアー ツール (SvcTraceViewer.exe) が使用されます。 これは、メッセージの内容を表示し、渡されている内容とコンテンツ ベースの相関関係の CorrelationQuery と一致するかどうかを正確に確認できるため、コンテンツベースの相関関係の問題をトラブルシューティングする場合に特に便利です。 WCF トレースの詳細については、「 サービス トレース ビューアー ツール (SvcTraceViewer.exe)、 トレースの構成、および トレースを使用したアプリケーションのトラブルシューティング」を参照してください。
コンテキスト交換の相関関係に関する一般的な問題
特定の種類の相関関係を正しく機能させるには、特定の種類のバインディングを使用する必要があります。 たとえば、要求と応答の相関関係( BasicHttpBindingなどの双方向バインディングが必要)、コンテキスト交換の相関関係 ( BasicHttpContextBinding などのコンテキストベースのバインドが必要) などがあります。 ほとんどのバインディングでは双方向の操作がサポートされているため、これは要求と応答の相関関係に関する一般的な問題ではありませんが、 BasicHttpContextBinding、 WSHttpContextBinding、 NetTcpContextBindingなど、コンテキストベースのバインディングはほんの一部です。 これらのバインディングのいずれかが使用されていない場合、ワークフロー サービスへの最初の呼び出しは成功しますが、後続の呼び出しは次の 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.
コンテキストの関連付けに使用されるコンテキスト情報は、双方向の操作を使用するときにコンテキストの関連付けを初期化するSendReply アクティビティにReceiveによって返すことができます。また、操作が一方向の場合は呼び出し元によって指定できます。 コンテキストが呼び出し元によって送信されなかったり、ワークフロー サービスによって返されたりしない場合は、後続の操作が呼び出されたときに、前に説明したのと同じ FaultException が返されます。
一般的な要求-応答関連付けの問題
要求と応答の関連付けは、ワークフロー サービスで双方向操作を実装するために Receive/SendReply ペアと、別の Web サービスで双方向操作を呼び出す Send/ReceiveReply ペアと共に使用されます。 WCF サービスで双方向操作を呼び出す場合、サービスは従来の命令型コード ベースの WCF サービスにすることも、ワークフロー サービスにすることもできます。 要求と応答の相関関係を使用するには、 BasicHttpBindingなどの双方向バインディングを使用する必要があり、操作は双方向である必要があります。
ワークフロー サービスに双方向の操作が並列で存在する場合、または Receive/SendReply または Send/ReceiveReply のペアが重複している場合、特に負荷の高いシナリオでは、 WorkflowServiceHost によって提供される暗黙的な関連付けハンドル管理が不十分であり、メッセージが正しくルーティングされない可能性があります。 この問題が発生しないようにするには、要求と応答の相関関係を使用する場合は、常に CorrelationHandle を明示的に指定することをお勧めします。 ワークフロー デザイナーのツールボックスの [メッセージング] セクションから SendAndReceiveReply テンプレートと ReceiveAndSendReply テンプレートを使用する場合、CorrelationHandleは既定で明示的に構成されます。 コードを使用してワークフローを構築する場合、 CorrelationHandle はペアの最初のアクティビティの CorrelationInitializers で指定されます。 次の例では、Receive アクティビティは、CorrelationHandleで指定された明示的な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.
Receive / SendReply ペアまたはSend/ReceiveReply ペア間の永続化は許可されません。 両方のアクティビティが完了するまで続く非永続(ノーパースト)ゾーンが作成されます。 遅延アクティビティなどのアクティビティがこの非永続化ゾーンにあり、ワークフローがアイドル状態になった場合、ホストがワークフローをアイドル状態で永続化するように構成されている場合でも、ワークフローは永続化されません。 永続化アクティビティなどのアクティビティが非永続化ゾーンで明示的に永続化しようとすると、致命的な例外が発生し、ワークフローが中止され、FaultException が呼び出し元に返されます。 致命的な例外メッセージは"System.InvalidOperationException: Persist アクティビティを非永続化ブロック内に含めることはできません。" です。 この例外は呼び出し元には返されませんが、追跡が有効になっている場合は確認できます。 呼び出し元に返される FaultException のメッセージは、「WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' が完了したため、操作を実行できませんでした」です。
要求と応答の相関関係の詳細については、「 Request-Reply」を参照してください。
一般的なコンテンツの相関関係の問題
コンテンツ ベースの相関関係は、ワークフロー サービスが複数のメッセージを受信し、交換されたメッセージ内のデータの一部が目的のインスタンスを識別する場合に使用されます。 コンテンツ ベースの関連付けでは、メッセージ内のこのデータ (顧客番号や注文 ID など) を使用して、メッセージを正しいワークフロー インスタンスにルーティングします。 このセクションでは、コンテンツ ベースの相関関係を使用するときに発生する可能性があるいくつかの一般的な問題について説明します。
識別データが一意であることを確認する
インスタンスを識別するために使用されるデータは、関連付けキーにハッシュされます。 データが一意でない場合、ハッシュされたキーで競合が発生し、メッセージが誤ってルーティングされる可能性があるため、関連付けに使用するデータが一意であることを保証する必要があります。 たとえば、顧客名のみに基づく相関関係では、同じ名前を持つ複数の顧客が存在する可能性があるため、競合が発生する可能性があります。 コロン (:)は、メッセージを関連付けるために使用されるデータの一部として使用しないでください。これは、メッセージ クエリのキーと値を区切って、その後ハッシュされる文字列を形成するために既に使用されているためです。 永続化が使用されている場合は、現在の識別データが以前に永続化されたインスタンスで使用されていないことを確認します。 永続化を一時的に無効にすると、この問題を特定するのに役立ちます。 WCF トレースは、計算された関連付けキーを表示するために使用でき、この種の問題のデバッグに役立ちます。
競合状態
メッセージを受信するサービスと実際に初期化されている相関関係との間には、少し時間の差があり、その間、フォローアップ メッセージは無視されます。 ワークフロー サービスが、一方向の操作でクライアントから渡されたデータを使用してコンテンツ ベースの相関関係を初期化し、呼び出し元がすぐにフォローアップ メッセージを送信する場合、この期間中、これらのメッセージは無視されます。 これは、双方向の操作を使用して相関関係を初期化するか、 TransactedReceiveScopeを使用して回避できます。
関連付けクエリの問題
関連付けクエリは、メッセージの関連付けに使用されるメッセージ内のデータを指定するために使用されます。 このデータは、XPath クエリを使用して指定します。 すべてが正しいように見えてもサービスへのメッセージがディスパッチされていない場合、トラブルシューティングの 1 つの方法は、XPath クエリの代わりにメッセージ データの値と一致するリテラル値を指定することです。 リテラル値を指定するには、 string 関数を使用します。 次の例では、MessageQuerySetに11445のリテラル値を使用するようにOrderIdを構成し、XPath クエリをコメント アウトします。
MessageQuerySet = new MessageQuerySet
{
{
"OrderId",
//new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
new XPathMessageQuery("string('11445')")
}
}
XPathクエリが正しく構成されておらず、関連付けデータが取得されない場合、次のメッセージを伴うエラーが返されます:"関連付けクエリによって空の結果セットが生成されました。" エンドポイントの関連付けクエリが正しく構成されていることを確認してください。これをトラブルシューティングする簡単な方法の 1 つは、前のセクションで説明したように、XPath クエリをリテラル値に置き換える方法です。 この問題は、[ 関連付け初期化子の追加 ] または [ CorrelationsOn Definition ] ダイアログ ボックスで XPath クエリ ビルダーを使用し、ワークフロー サービスがメッセージ コントラクトを使用している場合に発生する可能性があります。 次の例では、メッセージ コントラクト クラスが定義されています。
[MessageContract]
public class AddItemMessage
{
[MessageHeader]
public string CartId;
[MessageBodyMember]
public string Item;
}
このメッセージ コントラクトは、ワークフロー内の Receive アクティビティによって使用されます。 メッセージのヘッダー内の CartId は、メッセージを正しいインスタンスに関連付けるために使用されます。 ワークフロー デザイナーの関連付けダイアログを使用して CartId を取得する XPath クエリを作成すると、次の正しくない XPath クエリが生成されます。
sm:body()/xg0:AddItemMessage/xg0:CartId
この XPath クエリは、 Receive アクティビティがデータのパラメーターを使用した場合は正しいと思われますが、メッセージ コントラクトを使用しているため、正しくありません。 次の XPath クエリは、ヘッダーから CartId を取得するための正しい XPath クエリです。
sm:header()/tempuri:CartId
これは、メッセージの本文を調べることで確認できます。
<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>
次の例は、前のメッセージ コントラクトを使用してデータを受信するReceive操作用に構成されたAddItem アクティビティを示しています。 XPath クエリが正しく構成されています。
<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>