다음을 통해 공유


예외 및 오류 처리

예외는 서비스 또는 클라이언트 구현 내에서 로컬 오류 통신에 사용됩니다. 이와 반대로 오류는 서버에서 클라이언트로 또는 그 반대로 가는 경우와 같이 서비스 경계 너머로 이루어지는 오류 통신에도 사용되는 말입니다. 오류 외에, 전송 채널에서 전송별 메커니즘을 사용하여 전송 수준의 오류 통신을 수행하는 경우도 많습니다. 예를 들어 HTTP 전송에서는 404 등의 상태 코드를 사용하여 끝점 URL이 없는 경우(오류를 다시 보낼 끝점이 없음)를 나타냅니다. 이 문서는 사용자 지정 채널 작성자를 위한 안내 자료를 제공하는 세 개의 단원으로 구성되어 있습니다. 첫 단원에서는 예외를 정의하고 throw하는 방법에 대한 안내 자료를 제공합니다. 둘째 단원에서는 오류 생성 및 소비에 대한 안내 자료를 제공합니다. 셋째 단원에서는 추적 정보를 제공하여 사용자 지정 채널 사용자의 응용 프로그램 실행 문제 해결을 돕는 방법에 대해 설명합니다.

예외

예외를 throw할 경우 두 가지를 염두에 두어야 합니다. 첫째, 사용자가 예외에 적절하게 반응하는 정확한 코드를 쓸 수 있는 형식이어야 합니다. 둘째, 잘못된 것이 무엇이고, 실패의 영향은 무엇이며, 문제를 해결하는 방법이 무엇인지 사용자가 이해하기에 충분한 정보를 제공해야 합니다. 다음 단원에서는 WCF(Windows Communication Foundation) 채널의 예외 형식과 메시지에 대한 안내 자료를 제공합니다. .NET의 예외 디자인 지침 문서에도 예외에 대한 일반적인 안내 자료가 있습니다.

예외 형식

채널에서 throw되는 모든 예외는 System.TimeoutException, System.ServiceModel.CommunicationException이거나 CommunicationException에서 파생된 형식이어야 합니다. ObjectDisposedException 등의 예외도 throw될 수 있지만 이는 오직 호출 코드에서 채널을 잘못 사용한 것을 나타내기 위한 것입니다. 채널을 올바르게 사용한 경우에는 지정된 예외만 throw해야 합니다. WCF에서는 CommunicationException으로부터 파생되며 채널에서 사용하도록 디자인된 7가지 예외 형식을 제공합니다. CommunicationException에서 파생되며 시스템의 다른 부분에서 사용하도록 디자인된 다른 예외도 있습니다. 예외 형식은 다음과 같습니다.

예외 형식 의미 내부 예외 콘텐츠 복구 전략

AddressAlreadyInUseException

수신용으로 지정된 끝점 주소가 이미 사용 중입니다.

있는 경우 이 예외를 일으킨 전송 오류에 대한 세부 정보를 더 제공합니다. 예를 들면 다음과 같습니다. PipeException, HttpListenerException 또는 SocketException.

다른 주소를 지정하십시오.

AddressAccessDeniedException

프로세스에 수신용으로 지정된 끝점 주소에 대한 액세스가 허용되지 않습니다.

있는 경우 이 예외를 일으킨 전송 오류에 대한 세부 정보를 더 제공합니다. 예를 들면 PipeException 또는 HttpListenerException과 같습니다.

다른 자격 증명으로 시도해 보십시오.

CommunicationObjectFaultedException

사용 중인 ICommunicationObject가 Faulted 상태입니다. 자세한 내용은 상태 변경 이해를 참조하십시오. 개체에서 보류 중인 호출이 여러 개인 경우에는 한 호출에서만 실패와 관련된 예외가 throw되며, 나머지 호출에서는 CommunicationObjectFaultedException이 throw됩니다. 이 예외는 보통 응용 프로그램에서 예외를 간과하고 이미 실패한 개체를 사용하려는 경우에 throw되며, 원래 예외를 catch한 것과 다른 스레드에서 일어나는 경우가 많습니다.

있는 경우 내부 예외에 대한 세부 정보를 제공합니다.

새 개체를 만듭니다. 처음에 ICommunicationObject의 오류를 일으킨 것이 무엇인지에 따라 다른 복구 작업이 필요할 수도 있습니다.

CommunicationObjectAbortedException

사용 중인 ICommunicationObject가 중단되었습니다. 자세한 내용은 상태 변경 이해를 참조하십시오. CommunicationObjectFaultedException과 마찬가지로, 이 예외는 응용 프로그램에서 개체에 대해 Abort를 호출했으며 따라서 개체를 더 이상 사용할 수 없는 경우를 나타냅니다. 이러한 호출은 다른 스레드에서 이루어지는 경우도 많습니다.

있는 경우 내부 예외에 대한 세부 정보를 제공합니다.

새 개체를 만듭니다. 처음에 ICommunicationObject의 중단을 일으킨 것이 무엇인지에 따라 다른 복구 작업이 필요할 수도 있습니다.

EndpointNotFoundException

대상 원격 끝점이 수신 대기 상태가 아닙니다. 이는 끝점 주소에 잘못된 부분이 있거나, 주소를 확인할 수 없거나, 끝점이 다운된 경우에 발생할 수 있습니다. 예로는 DNS 오류, 큐 관리자를 사용할 수 없는 경우, 그리고 서비스가 실행되지 않는 경우가 포함됩니다.

내부 예외는 세부 정보(일반적으로 기본 전송에 대한 정보)를 제공합니다.

다른 주소를 지정하십시오. 또는 서비스가 다운된 경우 발신자가 잠시 기다렸다가 다시 시도할 수도 있습니다.

ProtocolException

끝점의 정책에 설명된 통신 프로토콜이 끝점 사이에서 일치하지 않습니다. 예를 들어 프레이밍 콘텐츠 형식이 일치하지 않거나 최대 메시지 크기가 초과된 경우일 수 있습니다.

있는 경우 특정 프로토콜 오류에 대한 세부 정보를 더 제공합니다. 예를 들어 QuotaExceededException은 오류의 원인이 MaxReceivedMessageSize 초과인 경우의 내부 예외입니다.

복구: 발신자와 받는 프로토콜의 설정이 일치하는지 확인하십시오. 여기 사용되는 방법 중 하나는 서비스 끝점의 메타데이터(정책)를 다시 가져온 다음 생성된 바인딩을 사용하여 채널을 다시 만드는 것입니다.

ServerTooBusyException

원격 끝점이 수신 대기 상태이지만 메시지를 처리할 준비가 되지 않았습니다.

있는 경우 내부 예외는 SOAP 오류 또는 전송 수준 오류의 세부 정보를 제공합니다.

복구: 기다렸다가 나중에 작업을 다시 시도하십시오.

TimeoutException

제한 시간을 초과하기 전에 작업을 완료하지 못했습니다.

제한 시간에 대한 세부 정보를 제공할 수 있습니다.

기다렸다가 나중에 작업을 다시 시도하십시오.

지정된 유형이 기존 예외 형식 모두와 다른 특정 복구 전략에 해당되는 경우에만 새 예외 형식을 정의합니다. 새 예외 형식을 정의하는 경우, 새 형식은 CommunicationException 또는 파생된 클래스 중 하나에서 파생된 것이어야 합니다.

예외 메시지

예외 메시지는 프로그램이 아닌 사용자를 대상으로 하기 때문에 사용자가 문제를 이해하고 해결하는 데 충분히 도움이 될 만한 정보를 제공해야 합니다. 좋은 예외 메시지의 3가지 주요 부분은 다음과 같습니다.

발생 상황. 사용자의 경험과 밀접한 용어를 사용하여 문제를 명확하게 설명합니다. 예를 들어 잘못된 예외 메시지의 예로는 "잘못된 구성 섹션"이 있습니다. 그러면 사용자는 구성 섹션에서 잘못된 부분이 어느 곳이며 잘못된 이유가 무엇인지 알 수 없습니다. 이 메시지를 좀더 개선하면 "잘못된 구성 섹션 <customBinding>"이 됩니다. "바인딩에 이미 myTransport라는 전송이 있기 때문에 myBinding이라는 바인딩에 myTransport라는 전송을 추가할 수 없습니다"로 만들면 메시지가 한결 더 나아집니다. 이 메시지는 사용자가 응용 프로그램의 구성 파일에서 쉽게 식별할 수 있는 용어와 이름을 사용한 매우 구체적인 메시지입니다. 하지만 여전히 몇 가지 주요 구성 요소가 빠져 있습니다.

오류의 중대성. 메시지에 오류의 의미가 명확하게 표시되어 있지 않으면 사용자는 치명적인 오류인지 무시해도 되는 오류인지 알 방법이 없습니다. 일반적으로 메시지를 통해 오류의 의미나 중대성을 알 수 있어야 합니다. 이전의 예를 개선하면 메시지는 "구성 오류 때문에 ServiceHost를 열지 못했습니다. 바인딩에 이미 myTransport라는 전송이 있기 때문에 myBinding이라는 바인딩에 myTransport라는 전송을 추가할 수 없습니다"가 될 수 있습니다.

사용자가 문제를 해결하는 방법. 메시지에서 가장 중요한 부분은 사용자가 문제를 해결할 수 있게 돕는 것입니다. 메시지에는 문제를 해결하기 위해 확인하거나 수정해야 할 사항에 대한 안내 자료 또는 힌트가 포함되어 있어야 합니다. 예를 들면 "구성 오류 때문에 ServiceHost를 열지 못했습니다. 바인딩에 이미 myTransport라는 전송이 있기 때문에 myBinding이라는 바인딩에 myTransport라는 전송을 추가할 수 없습니다. 바인딩에 전송이 하나 뿐인지 확인하십시오"가 될 수 있습니다.

오류 통신

SOAP 1.1과 SOAP 1.2는 모두 오류의 특정 구조를 정의합니다. 두 사양 사이에 약간의 차이는 있지만 일반적으로 Message 및 MessageFault 형식을 사용하여 오류를 만들고 소비합니다.

예외 및 오류 처리

SOAP에서는 오류 메시지를 오류 요소(이름이 **<env:Fault>**인 요소)를 **<env:Body>**의 자식으로 포함하는 메시지로만 정의합니다. 그림 1에 표시된 것과 같이 오류 요소의 콘텐츠는 SOAP 1.1과 SOAP 1.2 사이에서 약간 다릅니다. 하지만 System.ServiceModel.Channels.MessageFault 클래스에서는 이런 차이를 한 개체 모델로 정규화합니다.

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에서는 Sender 또는 Receiver 등의 5가지 허용되는 값을 faultCode에 정의하고 하위 코드 값을 포함할 수 있는 Subcode 요소를 정의합니다. 허용되는 오류 코드와 해당 의미의 목록을 보려면 SOAP 1.2 specification을 참조하십시오. SOAP 1.1의 메커니즘은 약간 다릅니다. 여기서는 Client 및 Server와 같은 4개의 faultCode 값을 정의하며, 이 값은 완전히 새로운 값을 정의하거나 점 표기법을 사용하여 더 구체적인 faultCodes로 만들 수 있습니다(예: Client.Authentication).

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에서 노출됩니다. 오류 세부 정보는 오류에 대한 추가 정보를 전달하는 데 사용되는 불투명 요소입니다. 오류와 함께 전달할 임의 구조의 세무 정보가 있는 경우에 유용합니다.

오류 생성

이 단원에서는 채널에서 검색된 오류나 채널에서 만든 메시지 속성에 대한 반응으로 오류를 생성하는 과정을 설명합니다. 일반적인 예로는 잘못된 데이터가 포함된 요청 메시지에 대한 반응으로 오류를 다시 보내는 경우가 있습니다.

오류를 생성할 때에는 사용자 지정 채널에서 오류를 직접 보내지 않고 예외를 throw한 다음 위의 계층에서 예외를 오류로 변환할 것인지 여부와 전송 방법을 결정하게 해야 합니다. 이 변환을 돕기 위해, 채널에서는 사용자 지정 채널에서 throw된 예외를 적절한 오류로 변환할 수 있는 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
}

이 패턴의 구현은 오류가 필요한 오류 조건의 계층 사이에서 throw된 예외에 해당 오류 생성기로 올바른 오류를 만들기에 충분한 정보가 있어야 한다는 것입니다. 사용자 지정 채널 작성자는 다양한 오류 조건에 해당하는 예외 형식을 정의할 수 있습니다(그러한 예외가 이미 존재하지 않는 경우). 채널 계층 사이를 이동하는 예외는 불투명 오류 데이터가 아닌 오류 조건을 전달해야 합니다.

오류 범주

일반적으로 오류에는 세 가지 범주가 있습니다.

  1. 전체 스택에 퍼지는 오류. 이러한 오류는 InvalidCardinalityAddressingException와 같이 채널 스택 내의 어느 계층에서나 발생할 수 있습니다.

  2. 흐름 트랜잭션이나 보안 역할에 관한 일부 오류의 예와 같이 스택에서 특정 계층 위의 어느 곳에서나 발생할 수 있는 오류.

  3. WS-RM 시퀀스 번호 오류와 같이 스택의 단일 계층에 전달되는 오류.

범주 1. 오류는 일반적으로 WS-Addressing 및 SOAP 오류입니다. WCF에서 제공되는 기본 FaultConverter 클래스에서는 WS-Addressing 및 SOAP에 지정된 오류 메시지에 해당되는 오류를 변환하기 때문에 이런 예외의 변환을 자신이 직접 처리할 필요가 없습니다.

범주 2. 오류는 계층에 대한 메시지 정보를 완전히 소비하지 않는 메시지에 계층에서 속성을 추가한 경우에 발생합니다. 높은 계층에서 메시지 속성에 추가로 메시지 정보를 처리하도록 요청하는 경우 이후에 오류가 검색될 수 있습니다. 이러한 채널에서는 이전에 지정한 GetProperty를 구현하여 높은 계층에서 올바른 오류를 다시 보낼 수 있게 합니다. 이러한 경우의 예에는 TransactionMessageProperty가 있습니다. 이 속성은 헤더에 있는 모든 데이터의 유효성을 완전히 검사하지 않고 메시지에 추가됩니다. 그 과정에서 DTC(Distributed Transaction Coordinator)에 연결해야 할 수도 있습니다.

범주 3. 오류는 프로세서 내의 단일 계층에서만 생성하여 보냅니다. 따라서 모든 예외는 계층 내에 포함됩니다. 채널 사이의 일관성을 향상시키고 유지 관리를 쉽게 하려면 사용자 지정 채널에서 내부 오류에 대해서도 이전에 지정한 패턴을 사용하여 오류 메시지를 생성해야 합니다.

받은 오류 해석

이 단원에서는 오류 메시지를 받을 때 적절한 예외를 생성하는 경우에 대한 안내 자료를 제공합니다. 스택의 모든 계층에서 메시지를 처리하는 경우의 의사 결정 트리는 다음과 같습니다.

  1. 계층에서 메시지가 잘못된 것으로 간주하는 경우에는 계층에서 ‘잘못된 메시지’ 처리를 수행해야 합니다. 이러한 처리는 계층별로 적용되지만 메시지의 삭제, 추적 또는 오류로 변환되는 예외 throw 등이 포함될 수도 있습니다. 예에는 보안에서 제대로 보호되지 않은 메시지를 받는 경우나 RM에서 시퀀스 번호가 잘못된 메시지를 받는 경우가 포함됩니다.

  2. 그렇지 않은 경우, 메시지가 계층에만 적용되는 오류 메시지이면 계층 상호 작용의 외부에서 메시지가 의미를 갖지 못하기 때문에 계층에서 오류 조건을 처리해야 합니다. 이 경우의 예로는 RM 채널 위의 계층에서는 의미가 없고 RM 채널 안에서만 오류가 발생하며 보류 중인 작업에서 throw되는 RM 시퀀스 거부 오류가 있습니다.

  3. 그렇지 않으면 Request() 또는 Receive()에서 메시지가 반환되어야 합니다. 여기에는 계층에서 오류를 인식하지만, 채널에서 오류가 발생하고 보류 중인 작업에서 오류가 throw되는 것을 의미하지는 않고 단지 요청이 실패했다는 사실만을 알리는 경우가 포함됩니다. 이러한 경우에 기능성을 개선하려면 계층에서 GetProperty<FaultConverter>를 구현하고, OnTryCreateException을 재정의하여 오류를 예외로 변환할 수 있는 FaultConverter 파생 클래스를 반환해야 합니다.

다음 개체 모델에서는 메시지를 예외로 변환하는 기능을 지원합니다.

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 처리를 수행합니다. 생성된 오류에는 MustUnderstand=true이고 이해되지 않은 모든 헤더의 이름이 포함된 NotUnderstood 헤더가 있습니다.

프로토콜 채널에서 MustUnderstand=true인 사용자 지정 헤더를 보낸 후 mustUnderstand 오류를 받은 경우에는 헤더를 보냈기 때문에 발생한 오류인지 여부를 확인해야 합니다. MessageFault 클래스에는 여기에 유용한 2개의 멤버가 있습니다.

public class MessageFault
{
    ...
    public bool IsMustUnderstandFault { get; }
    public static bool WasHeaderNotUnderstood(MessageHeaders headers, 
        string name, string ns) { }
    ...

}

IsMustUnderstandFault에서는 오류가 mustUnderstand 오류이면 true를 반환합니다. WasHeaderNotUnderstood에서는 지정된 이름과 네임스페이스의 헤더가 오류에 NotUnderstood 헤더로 포함되어 있으면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.

채널에서 MustUnderstand = true로 표시된 헤더를 전송하면 계층에서도 Exception Generation API 패턴을 구현하고 앞서 설명한 것과 같이 헤더에서 발생한 mustUnderstand 오류를 좀더 유용한 예외로 변환해야 합니다.

추적

.NET Framework에서는 디버거를 첨부하고 코드를 실행할 수 없는 경우 프로덕션 응용 프로그램 또는 일시적인 문제의 진단을 돕는 방법으로서 프로그램 실행을 추적하는 메커니즘을 제공합니다. 이 메커니즘의 핵심 구성 요소는 System.Diagnostics 네임스페이스에 있으며 다음으로 구성됩니다.

  • System.Diagnostics.TraceSource는 쓰려는 추적 정보의 소스이고 System.Diagnostics.TraceListenerTraceSource로부터 추적할 정보를 받아 수신기별 대상으로 출력하는 구체적인 수신기의 추상 기본 클래스입니다. 예를 들어 XmlWriterTraceListener에서는 추적 정보를 XML 파일로 출력합니다. 마지막으로 System.Diagnostics.TraceSwitch은 응용 프로그램 사용자가 추적의 자세한 정도를 추적할 수 있게 해 주며 일반적으로 구성에 지정됩니다.

  • 핵심 구성 요소 외에도 Service Trace Viewer 도구(SvcTraceViewer.exe)를 사용하여 WCF 추적을 검색할 수 있습니다. 해당 도구는 WCF에서 생성되는 추적 파일을 위해 디자인되었으며 XmlWriterTraceListener를 사용하여 작성되었습니다. 다음 그림에서는 추적에 관련된 다양한 구성 요소를 소개합니다.

예외 및 오류 처리

사용자 지정 채널에서 추적

사용자 지정 채널에서는 디버거를 실행 중인 응용 프로그램에 첨부할 수 없는 경우 문제의 진단을 돕기 위한 추적 메시지를 작성해야 합니다. 이 과정은 높은 수준의 작업 2개로 진행됩니다. 하나는 TraceSource를 인스턴스화하는 작업이고, 다른 하나는 메서드를 호출하여 추적을 작성하는 작업입니다.

TraceSource를 인스턴스화하면 지정한 문자열이 소스의 이름이 됩니다. 이 이름은 추적 소스를 구성(활성화/비활성화/추적 수준 설정)하는 데 사용됩니다. 이 이름은 추적 출력 자체에도 표시됩니다. 사용자 지정 채널에서는 추적 출력을 읽는 사람이 추적 정보가 오는 곳을 파악할 수 있도록 고유한 소스 이름을 사용해야 합니다. 일반적으로는 정보를 쓰는 어셈블리의 이름을 추적 소스의 이름으로 사용합니다. 예를 들어 WCF에서는 System.ServiceModel 어셈블리에서 쓰는 정보의 추적 소스로 System.ServiceModel을 사용합니다.

추적 소스가 있으면 TraceData, TraceEvent 또는 TraceInformation 메서드를 호출하여 추적 수신기에 추적 항목을 씁니다. 쓰는 각 추적 항목에 대해 이벤트의 형식을 TraceEventType에 정의된 이벤트 형식 중 하나로 분류해야 합니다. 구성에서 이 분류와 추적 수준 설정에 따라 추적 항목이 수신기로 출력되는지 여부가 결정됩니다. 예를 들어 구성에서 추적 수준을 Warning으로 설정하면 Warning, ErrorCritical 추적 항목을 쓰고 Information 및 Verbose 항목은 차단합니다. 다음은 추적 소스를 인스턴스화하고 Information 수준에서 항목을 쓰는 경우의 예입니다.

using System.Diagnostics;
//...
TraceSource udpSource=new TraceSource("Microsoft.Samples.Udp");
//...
udpsource.TraceInformation("UdpInputChannel received a message");
ms789039.Important(ko-kr,VS.100).gif 참고:
추적 출력을 읽는 사람이 출력이 온 위치를 파악할 수 있도록 추적 소스 이름을 지정하는 것이 좋습니다.

Trace Viewer와 통합

System.Diagnostics.XmlWriterTraceListener를 추적 수신기로 사용하여 채널에서 생성되는 추적을 Service Trace Viewer 도구(SvcTraceViewer.exe)에서 읽을 수 있는 형식으로 출력할 수 있습니다. 채널 개발자에게는 이 기능이 필요 없습니다. 응용 프로그램의 구성 파일에 이 추적 수신기를 구성할 필요가 있는 것은 응용 프로그램 사용자(또는 응용 프로그램 문제를 해결하는 사람)입니다. 예를 들어 다음 구성에서는 System.ServiceModelMicrosoft.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에는 추적 항목에 포함할 개체를 하나 이상 가져오는 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 Trace Viewer에서는 이전에 표시된 TraceRecord 요소의 스키마를 파악하고 자식 요소에서 데이터를 추출하여 표 형식으로 표시합니다. 채널에서는 Svctraceviewer.exe 사용자가 데이터를 읽는 데 도움이 되도록 구조적 응용 프로그램 데이터를 추적할 때 이 스키마를 사용해야 합니다.