例外とエラーの処理
例外は、サービスまたはクライアント実装内でエラーをローカルに伝達するために使用されます。一方、エラーは、サーバーからクライアントまたはクライアントからサーバーのように、サービス境界を越えてエラーを伝達するために使用されます。このようなエラーに加え、多くの場合、トランスポート チャネルはトランスポート固有の機構を使用して、トランスポート レベルのエラーを伝達します。たとえば、HTTP トランスポートは、404 などのステータス コードを使用して、存在しないエンドポイントの URL (エラーを返信するエンドポイントが存在しないこと) を伝達します。このドキュメントは、カスタム チャネル作成者にガイダンスを示す 3 つのセクションで構成されています。最初のセクションでは、例外を定義しスローする状況と方法に関するガイダンスを示します。2 番目のセクションでは、エラーの生成と使用に関するガイダンスを示します。3 番目のセクションでは、実行中のアプリケーションのトラブルシューティングを行う際に、カスタム チャネルのユーザーにとって役立つトレース情報を提供する方法について説明します。
例外
例外をスローする場合、2 つの点に留意します。まず、例外は、ユーザーがその例外に適切に対処できる正しいコードを作成できるような種類であることが必要です。もう 1 つは、例外では、問題点、エラーの影響、およびエラーの修正方法をユーザーが理解できるだけの情報を提供する必要があります。以下のセクションでは、Windows Communication Foundation (WCF) チャネルの例外の種類とメッセージに関するガイダンスを示します。また、「Design Guidelines for Exceptions」に記載された .NET の例外に関する一般的なガイダンスも示します。
例外の種類
チャネルがスローするすべての例外は、System.TimeoutException、System.ServiceModel.CommunicationException、または CommunicationException から派生した種類のいずれかである必要があります (ObjectDisposedException のような例外をスローすることもできますが、これは呼び出し元のコードがチャネルを誤用したことを示す場合だけです。チャネルが正しく使用されている場合は、指定の例外だけをスローする必要があります)。WCF には、CommunicationException から派生し、チャネルで使用するように設計された 7 種類の例外が用意されています。CommunicationException から派生した例外には、システムのその他の部分で使用するように設計されているものもあります。これらの例外の種類を以下に示します。
例外の種類 | 説明 | 内部例外の内容 | 回復方法 |
---|---|---|---|
リッスン用に指定されたエンドポイント アドレスは既に使用されています。 |
エラーの詳細情報が得られるようであれば、この例外の原因となったトランスポート エラーについての情報を提供します。例 : PipeException、HttpListenerException または SocketException |
別のアドレスで実行してください。 |
|
このプロセスは、リッスン用に指定されたエンドポイント アドレスへのアクセスを許可されていません。 |
エラーの詳細情報が得られるようであれば、この例外の原因となったトランスポート エラーについての情報を提供します。例 : PipeException または HttpListenerException |
別の資格情報を使用して試行します。 |
|
使用している ICommunicationObject が Faulted 状態になっています (詳細については、「状態変更の理解」を参照してください)。複数の呼び出しが保留になっているオブジェクトが Faulted 状態に遷移した場合、エラーに関連する例外をスローする呼び出しは 1 つだけであり、それ以外の呼び出しは CommunicationObjectFaultedException をスローします。通常、この例外がスローされるのは、アプリケーションが何らかの例外を認識しておらず、おそらく最初の例外をキャッチしたスレッド以外のスレッドで、既に Faulted 状態のオブジェクトを使用しようとしたためです。 |
詳細情報を使用できる場合は、内部例外についての詳細を示します。 |
新規オブジェクトを作成します。ICommunicationObject にエラーが発生した第一の原因によっては、回復するために他の作業が必要になることがあります。 |
|
使用している ICommunicationObject が Aborted 状態になっています (詳細については、「状態変更の理解」を参照してください)。CommunicationObjectFaultedException と同様に、この例外は、アプリケーションがおそらく別のスレッドからオブジェクトに対して Abort を呼び出したときに、オブジェクトが既に Aborted 状態であるため、使用できなくなっていることを示しています。 |
詳細情報を使用できる場合は、内部例外についての詳細を示します。 |
新規オブジェクトを作成します。ICommunicationObject が中止された第一の原因によっては、回復するために他の作業が必要になることがあります。 |
|
対象のリモート エンドポイントがリッスンしていません。これは、エンドポイント アドレスの一部に誤りがある、エンドポイント アドレスの一部を解決できない、またはエンドポイントがダウンしていることが原因として考えられます (DNS エラー、キュー マネージャを使用できない、サービスが実行されていないなど)。 |
この内部例外では、一般に、基になるトランスポートの詳細が示されます。 |
別のアドレスで実行してください。また、サービスがダウンしている場合は、送信元がしばらく待機し、再試行することもできます。 |
|
エンドポイントのポリシーで示されている通信プロトコルがエンドポイント間で一致していません (フレーム コンテンツの種類の不一致や、最大メッセージ サイズの超過など)。 |
詳細情報を使用できる場合は、特定のプロトコル エラーの詳細を示します。たとえば、MaxReceivedMessageSize を超えていることがエラーの原因である場合、QuotaExceededException が内部例外です。 |
回復 : 受信したプロトコル設定が送信側と一致していることを確認します。この方法の 1 つとして、サービス エンドポイントのメタデータ (ポリシー) を再度インポートし、生成されたバインディングを使用してチャネルを再作成します。 |
|
リモート エンドポイントはリッスンしていますが、メッセージを処理する準備ができていません。 |
詳細情報を使用できる場合は、内部例外で SOAP エラーまたはトランスポート レベルのエラーの詳細を示します。 |
回復 : しばらく待機し、後で操作を再試行します。 |
|
TimeoutException |
タイムアウト期間内に操作を完了できませんでした。 |
タイムアウトの詳細を示します。 |
しばらく待機し、後で操作を再試行します。 |
新しい例外の種類を定義するのは、その種類が既存の例外の種類のいずれとも異なる回復方法に対応する場合だけです。新しい例外の種類を定義する場合は、CommunicationException または派生クラスのいずれかから派生する必要があります。
例外メッセージ
例外メッセージは、プログラムではなくユーザーを対象としています。したがって、ユーザーが問題を理解し、解決する上で役立つ十分な情報を提供する必要があります。優れた例外メッセージに不可欠な 3 つの構成要素を以下に示します。
問題の内容。ユーザーの経験に関連する用語を使用して、問題を明確に説明します。たとえば、"無効な構成セクション" という例外メッセージは適切とはいえません。このようなメッセージでは、ユーザーは、どの構成セクションに誤りがあり、それがなぜ誤りなのか疑問を抱いたままになります。より適切なメッセージとしては、"無効な構成セクション <customBinding>" が考えられます。これをさらに改善し、"myBinding というバインディングには myTransport というトランスポートが既に含まれているため、このバインディングに myTransport というトランスポートを追加することはできません" というメッセージにします。これは、アプリケーションの構成ファイル内でユーザーが容易に特定できる用語と名前を使用した、非常に明確なメッセージです。ただし、まだ重要な要素がいくつか欠けています。
エラーの重大度。メッセージがエラーの意味を明確に示していない場合、ユーザーはそれが致命的なエラーかどうか、または無視できるのかどうか疑問を抱くと考えられます。一般に、メッセージではエラーの意味や重大度を示す必要があります。前述の例のメッセージは、"構成エラーが原因で ServiceHost を開くことができませんでした: myBinding というバインディングには myTransport というトランスポートが既に含まれているため、このバインディングに myTransport というトランスポートを追加することはできません" というメッセージに改善できます。
ユーザーが問題を修正する方法。メッセージの最も重要な要素は、ユーザーによる問題の修正を支援することにあります。メッセージには、問題を改善するためのチェックや修正の内容に関する何らかのガイダンスやヒントを含める必要があります。たとえば、"構成エラーが原因で ServiceHost を開くことができませんでした: myBinding というバインディングには myTransport というトランスポートが既に含まれているため、このバインディングに myTransport というトランスポートを追加することはできません。バインディングに含まれているトランスポートが 1 つだけであることを確認してください" というメッセージにします。
エラーの伝達
SOAP 1.1 および SOAP 1.2 では、エラーの具体的な構造が定義されています。この 2 つの仕様にはいくつかの違いがありますが、通常、Message 型と MessageFault 型を使用して、エラーを作成および使用します。
SOAP では、エラー メッセージとは、<env:Body> の子要素としてエラー要素 (<env:Fault> という名前の要素) だけを含むメッセージと定義されています。図 1 に示すように、エラー要素の内容は SOAP 1.1 と SOAP 1.2 で若干異なります。ただし、次のように、System.ServiceModel.Channels.MessageFault クラスでは、これらの違いを 1 つのオブジェクト モデルに正規化します。
public abstract class MessageFault
{
protected MessageFault();
public virtual string Actor { get; }
public virtual string Node { get; }
public static string DefaultAction { get; }
public abstract FaultCode Code { get; }
public abstract bool HasDetail { get; }
public abstract FaultReason Reason { get; }
public T GetDetail<T>();
public T GetDetail<T>( XmlObjectSerializer serializer);
public System.Xml.XmlDictionaryReader GetReaderAtDetailContents();
// other methods omitted
}
Code
プロパティは、env:Code (または SOAP 1.1 の faultCode) に対応し、エラーの種類を識別します。SOAP 1.2 では、faultCode の 5 つの許容値 (Sender や Receiver など) が定義されており、サブコード値を格納できる Subcode 要素も定義されています (使用できるエラー コードとその意味の一覧については、SOAP 1.2 の仕様を参照してください)。SOAP 1.1 の機構は若干異なります。SOAP 1.1 では、faultCode の 4 つの値 (Client や Server など) が定義されています。これらの値は、まったく新しい値を定義するか、ドット表記を使用して Client.Authentication のようなより具体的な faultCodes を作成することによって拡張できます。
MessageFault を使用してエラーをプログラミングする場合、FaultCode.Name と FaultCode.Namespace は、SOAP 1.2 の env:Code または SOAP 1.1 の faultCode の名前と名前空間に割り当てられます。FaultCode.SubCode は、SOAP 1.2 では env:Subcode に割り当てられ、SOAP 1.1 では null になります。
エラーをプログラムによって区別する場合は、新しいエラー サブコード (SOAP 1.1 を使用する場合は新しいエラー コード) を作成します。これは、新しい例外の種類を作成することに似ています。SOAP 1.1 エラー コードではドット表記を使用しないようにすることをお勧めします (WS-I Basic Profile でも、エラー コードのドット表記の使用は推奨されていません)。
public class FaultCode
{
public FaultCode(string name);
public FaultCode(string name, FaultCode subCode);
public FaultCode(string name, string ns);
public FaultCode(string name, string ns, FaultCode subCode);
public bool IsPredefinedFault { get; }
public bool IsReceiverFault { get; }
public bool IsSenderFault { get; }
public string Name { get; }
public string Namespace { get; }
public FaultCode SubCode { get; }
// methods omitted
}
Reason
プロパティは、env:Reason (または SOAP 1.1 の faultString) に対応しています。これは、例外のメッセージと同様に、ユーザーが判読できるエラー状態の記述です。FaultReason クラス (および SOAP の env:Reason/faultString) には、グローバリゼーションのために、複数の変換を使用するためのサポートが組み込まれています。
public class FaultReason
{
public FaultReason(FaultReasonText translation);
public FaultReason(IEnumerable<FaultReasonText> translations);
public FaultReason(string text);
public SynchronizedReadOnlyCollection<FaultReasonText> Translations
{
get;
}
}
エラーの詳しい内容は、GetDetail<T> や GetReaderAtDetailContents() などのさまざまなメソッドを使用して、MessageFault で公開されます。エラーの詳細は、エラーに関する追加情報を伝達するための不透明な要素です。これは、エラーと共に伝達する任意の構造化された詳細がある場合に役立ちます。
エラーの生成
このセクションでは、チャネルまたはチャネルによって作成されたメッセージ プロパティで検出されるエラー状態に応じてエラーを生成するプロセスについて説明します。一般的な例として、無効なデータが含まれた要求メッセージに対するエラーの送信が挙げられます。
エラーの生成時には、カスタム チャネルからエラーを直接送信するのではなく、例外をスローするようにし、その例外をエラーに変換するかどうかの判断とエラーの送信方法の決定は上位のレイヤで行います。この変換を支援するために、チャネルは FaultConverter
を実装し、カスタム チャネルがスローした例外を適切なエラーに変換できるようにします。FaultConverter
は、次のように定義します。
public class FaultConverter
{
public static FaultConverter GetDefaultFaultConverter(
MessageVersion version);
protected abstract bool OnTryCreateFaultMessage(
Exception exception,
out Message message);
public bool TryCreateFaultMessage(
Exception exception,
out Message message);
}
カスタム エラーを生成する各チャネルは FaultConverter
を実装し、GetProperty<FaultConverter>
の呼び出しからこれを返す必要があります。カスタム OnTryCreateFaultMessage
実装では、例外をエラーに変換するか、内部チャネルの FaultConverter
に委任する必要があります。チャネルがトランスポートの場合は、例外を変換するか、エンコーダの FaultConverter
または WCF に用意された既定の FaultConverter
に委任する必要があります。既定の FaultConverter
は、WS-Addressing および SOAP で指定されたエラー メッセージに対応するエラーを変換します。OnTryCreateFaultMessage
実装の例を次に示します。
public override bool OnTryCreateFaultMessage(Exception exception,
out Message message)
{
if (exception is ...)
{
message = ...;
return true;
}
#if IMPLEMENTING_TRANSPORT_CHANNEL
FaultConverter encoderConverter =
this.encoder.GetProperty<FaultConverter>();
if ((encoderConverter != null) &&
(encoderConverter.TryCreateFaultMessage(
exception, out message)))
{
return true;
}
FaultConverter defaultConverter =
FaultConverter.GetDefaultFaultConverter(
this.channel.messageVersion);
return defaultConverter.TryCreateFaultMessage(
exception,
out message);
#else
FaultConverter inner =
this.innerChannel.GetProperty<FaultConverter>();
if (inner != null)
{
return inner.TryCreateFaultMessage(exception, out message);
}
else
{
message = null;
return false;
}
#endif
}
このパターンでは、エラーを必要とするエラー状態についてレイヤ間でスローされる例外に、対応するエラー ジェネレータが適切なエラーを作成できるだけの情報が含まれている必要があります。カスタム チャネル作成者は、さまざまなエラー状態に対応する例外の種類を定義できます (特定のエラー状態に対応する既存の例外がない場合)。チャネル レイヤを越えて伝播する例外では、不明瞭なエラー データではなく、エラー状態を伝える必要があります。
エラーのカテゴリ
一般に、エラーは次の 3 つのカテゴリに分類されます。
- スタック全体にわたるエラー。このようなエラーは、チャネル スタックのどのレイヤでも発生する可能性があります (例 : InvalidCardinalityAddressingException)。
- スタックの特定のレイヤより上位の任意の場所で発生する可能性があるエラー (例 : フローされたトランザクションやセキュリティ ロールに関するエラー)。
- スタックの単一のレイヤを対象とするエラー (例 : WS-RM シーケンス番号エラー)。
カテゴリ 1 : 一般に、WS-Addressing エラーおよび SOAP エラーです。WCF に用意された FaultConverter 基本クラスでは、WS-Addressing および SOAP で指定されたエラー メッセージに対応するエラーを変換するため、カスタム チャネル作成者がこれらの例外の変換を処理する必要はありません。
カテゴリ 2 : レイヤに関するメッセージ情報を完全に使用しているわけではないメッセージに対して、そのレイヤがプロパティを追加したときに発生します。後で上位のレイヤがメッセージ情報をさらに処理するために、メッセージ プロパティを要求したときに、エラーが検出されることがあります。このようなチャネルでは、前述の GetProperty
を実装して、上位のレイヤが適切なエラーを返すことができるようにする必要があります。プロパティの例として、TransactionMessageProperty があります。このプロパティは、ヘッダー内のすべてのデータが完全には検証されずにメッセージに追加されます (この検証には、分散トランザクション コーディネータ (DTC) への接続が必要になることがあります)。
カテゴリ 3 : エラーは、プロセッサ内の単一のレイヤによって生成され、送信されるだけです。したがって、すべての例外はそのレイヤ内に含まれます。チャネル間の整合性を向上させ、保守を容易にするために、カスタム チャネルでは、前述のパターンを使用して、内部エラーについてもエラー メッセージを生成することをお勧めします。
受信したエラーの解釈
このセクションでは、エラー メッセージを受信したときに、適切な例外を生成するためのガイダンスを示します。スタックのすべてのレイヤにおけるメッセージ処理に関するデシジョン ツリーを以下に示します。
- レイヤがメッセージを無効と見なした場合、レイヤは "無効なメッセージ" の処理を実行する必要があります。このような処理はレイヤに固有のものですが、メッセージの破棄、トレース、エラーに変換される例外のスローなどの処理が可能です。たとえば、適切に保護されていないメッセージをセキュリティが受信した場合や、RM が不正なシーケンス番号を持つメッセージを受信した場合などです。
- メッセージが特定のレイヤに適用されるエラー メッセージであり、そのレイヤの対話以外では意味がないものである場合、該当のレイヤがエラー状態を処理する必要があります。この一例として、RM シーケンス拒否エラーが挙げられます。これは、RM チャネルにエラーが発生し、保留中の操作からスローされていることを示しており、RM チャネルより上位のレイヤにとっては意味のないエラーです。
- それ以外の場合は、Request() または Receive() からメッセージを返すようにします。たとえば、レイヤはエラーを認識しているが、そのエラーは要求が失敗したことを示しているにすぎず、チャネルにエラーが発生し、保留中の操作からスローされていることを意味しているわけではない場合などです。このような場合にユーザビリティを向上させるには、レイヤで
GetProperty<FaultConverter>
を実装し、FaultConverter
派生クラスを返すようにします。この派生クラスは、OnTryCreateException
をオーバーライドすることで、エラーを例外に変換できます。
次のオブジェクト モデルは、メッセージから例外への変換をサポートします。
public class FaultConverter
{
public static FaultConverter GetDefaultFaultConverter(
MessageVersion version);
protected abstract bool OnTryCreateException(
Message message,
MessageFault fault,
out Exception exception);
public bool TryCreateException(
Message message,
MessageFault fault,
out Exception exception);
}
チャネル レイヤは、GetProperty<FaultConverter>
を実装することで、エラー メッセージから例外への変換をサポートできます。これを行うには、OnTryCreateException
をオーバーライドし、エラー メッセージを検査します。エラー メッセージを認識した場合は、変換を実行します。それ以外の場合は、エラー メッセージの変換を内部チャネルに要求します。トランスポート チャネルでは、FaultConverter.GetDefaultFaultConverter に既定の SOAP/WS-Addressing FaultConverter の取得を委任する必要があります。
一般的な実装は、次のようになります。
public override bool OnTryCreateException(
Message message,
MessageFault fault,
out Exception exception)
{
if (message.Action == "...")
{
exception = ...;
return true;
}
// OR
if ((fault.Code.Name == "...") && (fault.Code.Namespace == "..."))
{
exception = ...;
return true;
}
if (fault.IsMustUnderstand)
{
if (fault.WasHeaderNotUnderstood(
message.Headers, "...", "..."))
{
exception = new ProtocolException(...);
return true;
}
}
#if IMPLEMENTING_TRANSPORT_CHANNEL
FaultConverter encoderConverter =
this.encoder.GetProperty<FaultConverter>();
if ((encoderConverter != null) &&
(encoderConverter.TryCreateException(
message, fault, out exception)))
{
return true;
}
FaultConverter defaultConverter =
FaultConverter.GetDefaultFaultConverter(
this.channel.messageVersion);
return defaultConverter.TryCreateException(
message, fault, out exception);
#else
FaultConverter inner =
this.innerChannel.GetProperty<FaultConverter>();
if (inner != null)
{
return inner.TryCreateException(message, fault, out exception);
}
else
{
exception = null;
return false;
}
#endif
}
明確な回復シナリオが用意されたエラー状態については、ProtocolException
の派生クラスを定義することを検討してください。
MustUnderstand の処理
SOAP には、必須のヘッダーが受信側で認識されなかったことを通知するための一般的なエラーが定義されています。このエラーは、mustUnderstand エラーと呼ばれます。WCF では、カスタム チャネルで mustUnderstand エラーを生成することはありません。代わりに、WCF 通信スタックの最上位にある WCF ディスパッチャが、MustUndestand=true としてマークされたすべてのヘッダーが基になるスタックで認識されているかどうかをチェックします。認識されていないヘッダーが見つかった場合、その時点で mustUnderstand エラーが生成されます (ユーザーは、この mustUnderstand の処理を無効にし、すべてのメッセージ ヘッダーをアプリケーションで受信するようにすることができます。その場合、mustUnderstand の処理はアプリケーションが実行します)。生成されたエラーには、NotUnderstood ヘッダーが含まれます。このヘッダーには、MustUnderstand=true でマークされたヘッダーの中で、認識されなかったすべてのヘッダーの名前が含まれています。
プロトコル チャネルから MustUnderstand=true でマークされたカスタム ヘッダーを送信し、mustUnderstand エラーを受信した場合、そのエラーが送信したヘッダーに起因するものかどうかを確認する必要があります。MessageFault
クラスには、このために役立つ 2 つのメンバが存在します。
public class MessageFault
{
...
public bool IsMustUnderstandFault { get; }
public static bool WasHeaderNotUnderstood(MessageHeaders headers,
string name, string ns) { }
...
}
エラーが mustUnderstand エラーの場合、IsMustUnderstandFault
は true を返します。指定した名前空間と名前を持つヘッダーが NotUnderstood ヘッダーとしてエラーに含まれている場合、WasHeaderNotUnderstood
は true を返します。それ以外の場合は、false を返します。
MustUnderstand = true でマークされたヘッダーをチャネルで出力する場合は、該当のレイヤも例外生成 API パターンを実装し、出力したヘッダーが原因で発生した mustUnderstand エラーを前述のより有用な例外に変換する必要があります。
トレース
デバッガをアタッチしてコードを段階的に実行できない場合に、運用アプリケーションや断続的な問題の診断を支援する 1 つの方法として、.NET Framework にはプログラムの実行をトレースする機構が用意されています。この機構のコア コンポーネントは System.Diagnostics 名前空間にあり、以下で構成されます。
- System.Diagnostics.TraceSource は、書き込むトレース情報のソースです。System.Diagnostics.TraceListener は、TraceSource からトレースする情報を受け取り、リスナ固有の送信先に出力する具象リスナの抽象基本クラスです。たとえば、XmlWriterTraceListener は、トレース情報を XML ファイルに出力します。最後に、System.Diagnostics.TraceSwitch を使用すると、アプリケーション ユーザーがトレースの詳細出力レベルを制御できます。通常、このクラスは構成で指定します。
- コア コンポーネントに加え、Service TraceViewer Tool (SvcTraceViewer.exe) を使用すると、WCF のトレースを表示および検索できます。このツールは、WCF によって生成され、XmlWriterTraceListener を使用して書き込まれるトレース ファイル用に特別に設計されています。トレースに関与するさまざまなコンポーネントを次の図に示します。
カスタム チャネルからのトレース
実行中のアプリケーションにデバッガをアタッチできないときに問題の診断を支援するために、カスタム チャネルはトレース メッセージを書き込む必要あります。この場合、TraceSource のインスタンス化と、トレースを書き込むためのメソッドの呼び出しの 2 つの高度なタスクが必要となります。
TraceSource をインスタンス化する場合、指定した文字列が対象のソースの名前になります。この名前を使用して、トレース ソースを構成 (有効化/無効化/トレース レベルの設定) します。また、トレース出力にもこの名前が表示されます。カスタム チャネルは、一意のソース名を使用して、トレース出力の利用者にトレース情報のソースがわかるようにする必要があります。トレース ソースの名前として、情報を書き込むアセンブリの名前を使用するのが一般的です。たとえば、WCF では、System.ServiceModel アセンブリから書き込まれる情報のトレース ソースとして、System.ServiceModel を使用します。
トレース ソースを用意したら、TraceData、TraceEvent、または TraceInformation の各メソッドを呼び出して、トレース エントリをトレース リスナに書き込みます。書き込む各トレース エントリのイベントの種類は、TraceEventType に定義されたイベントの種類のいずれかとして分類する必要があります。この分類と構成でのトレース レベルの設定によって、トレース エントリをリスナに出力するかどうかが決まります。たとえば、構成でトレース レベルを Warning に設定すると、Warning、Error、および Critical の各トレース エントリを書き込むことができますが、Information エントリと Verbose エントリはブロックされます。トレース ソースをインスタンス化し、Information レベルでエントリを書き込む例を次に示します。
using System.Diagnostics;
//...
TraceSource udpSource=new TraceSource("Microsoft.Samples.Udp");
//...
udpsource.TraceInformation("UdpInputChannel received a message");
メモ : |
---|
カスタム チャネル固有のトレース ソース名を指定して、トレース出力の利用者に出力のソースがわかるようにすることを強くお勧めします。 |
トレース ビューアとの統合
トレース リスナとして System.Diagnostics.XmlWriterTraceListener を使用すると、チャネルによって生成されたトレースを Service TraceViewer Tool (SvcTraceViewer.exe) で読み取り可能な形式で出力できます。これは、チャネル開発者が行う必要はありません。アプリケーション ユーザー (またはアプリケーションのトラブルシューティング担当者) が、アプリケーションの構成ファイルでこのトレース リスナを構成する必要があります。たとえば、次の構成では、System.ServiceModel と Microsoft.Samples.Udp
の両方から TraceEventsFile.e2e
というファイルにトレース情報が出力されます。
<configuration>
<system.diagnostics>
<sources>
<!-- configure System.ServiceModel trace source -->
<source name="System.ServiceModel" switchValue="Verbose"
propagateActivity="true">
<listeners>
<add name="e2e" />
</listeners>
</source>
<!-- configure Microsoft.Samples.Udp trace source -->
<source name="Microsoft.Samples.Udp" switchValue="Verbose" >
<listeners>
<add name="e2e" />
</listeners>
</source>
</sources>
<!--
Define a shared trace listener that outputs to TraceFile.e2e
The listener name is e2e
-->
<sharedListeners>
<add name="e2e" type="System.Diagnostics.XmlWriterTraceListener"
initializeData=".\TraceFile.e2e"/>
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
</configuration>
構造化されたデータのトレース
System.Diagnostics.TraceSource には、トレース エントリに含まれる 1 つ以上のオブジェクトを取得する TraceData メソッドがあります。通常、System.Object.ToString メソッドは各オブジェクトに対して呼び出され、生成された文字列はトレース エントリの一部として書き込まれます。System.Diagnostics.XmlWriterTraceListener を使用してトレースを出力する場合、データ オブジェクトとして System.Xml.Xpath.IXPathNavigable を TraceData に渡すことができます。生成されるトレース エントリには、System.Xml.Xpath.XPathNavigator によって提供された XML が含まれます。XML アプリケーション データが含まれたエントリの例を次に示します。
<E2ETraceEvent xmlns="https://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="...">
<EventID>12</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2006-01-13T22:58:03.0654832Z" />
<Source Name="Microsoft.ServiceModel.Samples.Udp" />
<Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
<Execution ProcessName="UdpTestConsole"
ProcessID="3348" ThreadID="4" />
<Channel />
<Computer>COMPUTER-LT01</Computer>
</System>
<!-- XML application data -->
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord
Severity="Information"
xmlns="…">
<TraceIdentifier>some trace id</TraceIdentifier>
<Description>EndReceive called</Description>
<AppDomain>UdpTestConsole.exe</AppDomain>
<Source>UdpInputChannel</Source>
</TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
WCF トレース ビューアは、上記の TraceRecord 要素のスキーマを認識し、その子要素からデータを抽出して表形式で表示します。チャネルで構造化されたアプリケーション データをトレースするときには、このスキーマを使用して Svctraceviewer.exe のユーザーがデータを判読しやすいようにします。