오류 보내기 및 받기

SOAP 오류는 오류 조건 정보를 서비스에서 클라이언트로 전달하고 이중 클라이언트의 경우에는 상호 운용 가능한 방식으로 클라이언트에서 서비스로 전달합니다. 일반적으로 서비스는 사용자 지정 오류 내용을 정의하고 이들을 반환할 수 있는 작업을 지정합니다. (자세한 내용은 오류 정의 및 지정을 참조하세요.) 이 항목에서는 해당 오류 조건이 발생했을 때 서비스 또는 이중 클라이언트가 이러한 오류를 보내는 방법과 클라이언트 또는 서비스 애플리케이션이 이러한 오류를 처리하는 방법에 대해 설명합니다. WCF(Windows Communication Foundation) 애플리케이션의 오류 처리에 대한 개요는 계약 및 서비스의 오류 지정 및 처리를 참조하세요.

SOAP 오류 보내기

선언된 SOAP 오류는 작업에 사용자 지정 SOAP 오류 유형을 지정하는 System.ServiceModel.FaultContractAttribute가 있는 오류입니다. 선언되지 않은 SOAP 오류는 작업 계약에 지정되지 않은 오류입니다.

선언된 오류 보내기

선언된 SOAP 오류를 보내려면 SOAP 오류가 적합한 오류 조건을 검색하고 새 System.ServiceModel.FaultException<TDetail>을 throw합니다. 여기서, 형식 매개 변수는 해당 작업의 FaultContractAttribute에 지정된 형식의 새 개체입니다. 다음 코드 예에서는 FaultContractAttribute를 사용하여 SampleMethod 작업이 세부 형식이 GreetingFault인 SOAP 오류를 반환할 수 있음을 지정합니다.

[OperationContract]
[FaultContractAttribute(
  typeof(GreetingFault),
  Action="http://www.contoso.com/GreetingFault",
  ProtectionLevel=ProtectionLevel.EncryptAndSign
  )]
string SampleMethod(string msg);
<OperationContract, FaultContractAttribute(GetType(GreetingFault), Action:="http://www.contoso.com/GreetingFault", ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Function SampleMethod(ByVal msg As String) As String

GreetingFault 오류 정보를 클라이언트에게 전달하려면 적합한 오류 조건을 catch하고 다음 코드 예제처럼 새 System.ServiceModel.FaultException<TDetail> 개체가 인수인 GreetingFault 유형의 새 GreetingFault을 throw합니다. 클라이언트가 WCF 클라이언트 애플리케이션이면 형식이 GreetingFault 형식의 System.ServiceModel.FaultException<TDetail>인 관리되는 예외가 됩니다.

throw new FaultException<GreetingFault>(new GreetingFault("A Greeting error occurred. You said: " + msg));
    Throw New FaultException(Of GreetingFault)(New GreetingFault("A Greeting error occurred. You said: " & msg))
End If

선언되지 않은 오류 보내기

선언되지 않은 오류를 보내는 것은 WCF 애플리케이션에서 문제를 신속하게 진단하고 디버깅하는 데 유용하지만 디버깅 도구로서의 유용성에는 한계가 있습니다. 일반적으로 디버깅할 때 ServiceDebugBehavior.IncludeExceptionDetailInFaults 속성을 사용하는 것이 좋습니다. 이 값을 true로 설정하면 클라이언트에 FaultException<TDetail> 형식의 ExceptionDetail 예외와 같은 오류가 발생합니다.

Important

관리 되는 예외는 내부 애플리케이션 정보를 노출할 수, 있으므로 설정 ServiceBehaviorAttribute.IncludeExceptionDetailInFaultsServiceDebugBehavior.IncludeExceptionDetailInFaultstrue WCF 클라이언트에서는 개인적으로 포함 하 여 내부 서비스 작업 예외에 대 한 정보를 허용 하려면 식별할 수 있는 정보나 기타 중요 한 정보입니다.

그러므로 임시로 서비스 애플리케이션을 디버깅하려는 경우 권장되는 유일한 방법은 ServiceBehaviorAttribute.IncludeExceptionDetailInFaults 또는 ServiceDebugBehavior.IncludeExceptionDetailInFaultstrue로 설정하는 것입니다. 또한 이러한 방법으로 처리되지 않은 관리 예외를 반환하는 메서드에 대한 WSDL에는 ExceptionDetail 형식의 FaultException<TDetail>에 대한 계약이 포함되어 있지 않습니다. 디버깅 정보를 제대로 얻으려면 클라이언트는 System.ServiceModel.FaultException 개체로 WCF 클라이언트에 반환되는 알 수 없는 SOAP 오류의 가능성을 예상해야 합니다.

선언되지 않은 SOAP 오류를 보내려면 System.ServiceModel.FaultException 개체(즉, 제네릭 형식 FaultException<TDetail>이 아님)를 throw하고 문자열을 생성자에게 전달합니다. 이것은 FaultException<TDetail>.ToString 메서드를 호출하여 문자열을 사용할 수 있는 throw된 System.ServiceModel.FaultException 예외로 WCF 클라이언트 애플리케이션에 노출됩니다.

참고 항목

문자열 형식의 SOAP 오류를 선언한 다음 서비스에서 형식 매개 변수가 FaultException<TDetail>System.String로 throw하면 문자열 값이 FaultException<TDetail>.Detail 속성에 지정되며 FaultException<TDetail>.ToString에서 사용할 수 없습니다.

오류 처리

WCF 클라이언트에서 통신 중에 발생하는 클라이언트 애플리케이션 관련 SOAP 오류는 관리되는 예외로 발생합니다. 프로그램 실행 중에 발생할 수 있는 예외가 여러 가지 있지만 WCF 클라이언트 프로그래밍 모델을 사용하는 애플리케이션은 통신 결과로 다음과 같은 두 가지 형식의 예외를 처리할 수 있습니다.

작업이 지정된 제한 시간을 초과하면 TimeoutException 개체가 throw됩니다.

서비스나 클라이언트에 복구할 수 있는 통신 오류 조건이 있는 경우 CommunicationException 개체가 throw됩니다.

CommunicationException 클래스에는 두 가지 중요한 파생 형식인 FaultException과 제네릭 FaultException<TDetail> 형식이 있습니다.

수신자가 작업 계약에 예상되지 않거나 지정되지 않은 오류를 받으면 FaultException 예외가 throw됩니다. 일반적으로 이러한 예외는 애플리케이션이 디버깅 중이고 서비스의 ServiceDebugBehavior.IncludeExceptionDetailInFaults 속성이 true로 설정된 경우 발생합니다.

양방향 작업(즉, FaultException<TDetail>OperationContractAttribute로 설정된 IsOneWay 특성이 있는 메서드)에 대한 응답으로 작업 계약에 지정된 오류를 받은 경우 클라이언트에서 false 예외가 throw됩니다.

참고 항목

WCF 서비스에 ServiceBehaviorAttribute.IncludeExceptionDetailInFaults 또는 ServiceDebugBehavior.IncludeExceptionDetailInFaults 속성이 true로 설정된 경우 클라이언트는 이를 ExceptionDetail 형식의 선언되지 않은 FaultException<TDetail>로 표시됩니다. 클라이언트는 이러한 특정 오류를 catch하거나 FaultException에 대한 catch 블록의 오류를 처리할 수 있습니다.

일반적으로 FaultException<TDetail>, TimeoutExceptionCommunicationException 예외만 클라이언트와 서비스에 관련된 것입니다.

참고 항목

물론 다른 예외도 발생합니다. 예기치 않은 예외가 System.OutOfMemoryException과 같은 오류를 포함합니다. 일반적으로 애플리케이션은 그러한 메서드를 catch하지 않아야 합니다.

올바른 순서로 오류 예외 catch

FaultException<TDetail>FaultException에서 파생되고 FaultExceptionCommunicationException에서 파생되므로 적합한 순서로 이러한 예외를 catch하는 것이 중요합니다. 예를 들어 먼저 CommunicationException을 catch하는 try/catch 블록이 있는 경우 모든 지정된 SOAP 오류와 지정되지 않은 SOAP 오류가 여기서 처리됩니다. 사용자 지정 FaultException<TDetail> 예외를 처리할 이후 catch 블록은 호출되지 않습니다.

하나의 작업이 여러 개의 지정된 오류를 반환할 수 있습니다. 각 오류는 고유한 형식이며 별도로 처리해야 합니다.

채널을 닫을 때 예외 처리

앞에서 설명한 내용은 대부분 애플리케이션 메시지, 즉 클라이언트 애플리케이션이 WCF 클라이언트 개체에서 작업을 호출하는 경우 클라이언트가 명시적으로 보낸 메시지를 처리하는 동안 전송된 오류와 관련된 것입니다.

로컬 개체 외에도 개체를 삭제하면 재활용 프로세스 중에 발생하는 예외를 발생시키거나 마스킹할 수 있습니다. WCF 클라이언트 개체를 사용할 때도 비슷한 일이 발생할 수 있습니다. 작업을 호출할 때 설정된 연결을 통해 메시지를 보내게 됩니다. 연결을 완전히 종료할 수 없거나 연결이 이미 종료된 경우, 모든 작업이 제대로 반환되어도 채널을 닫으면 예외가 throw될 수 있습니다.

일반적으로 클라이언트 개체 채널은 다음 중 한 가지 방법으로 닫힙니다.

  • WCF 클라이언트 개체가 재활용되는 경우.

  • 클라이언트 애플리케이션이 ClientBase<TChannel>.Close를 호출하는 경우

  • 클라이언트 애플리케이션이 ICommunicationObject.Close를 호출하는 경우

  • 클라이언트 애플리케이션이 세션에 대한 종료 작업을 호출하는 경우

모든 경우에 채널을 닫으면 애플리케이션 수준에서 복잡한 기능을 지원할 메시지를 보낼 수 있는 기본 채널을 닫도록 채널에 지시합니다. 예를 들어 계약에 세션이 필요한 경우 세션이 설정될 때까지 바인딩 과정에서 서비스 채널과 메시지를 교환하여 세션을 설정합니다. 채널이 닫히면 기본 세션 채널은 세션이 종료되었음을 서비스에 알립니다. 이 때 채널이 이미 중단되었거나 닫혔거나 사용할 수 없는 경우(예: 네트워크 케이블이 연결되지 않은 경우) 클라이언트 채널은 세션이 종료되었으며 예외가 발생할 수 있음을 서비스 채널에 알릴 수 없습니다.

필요한 경우 채널 중단

채널을 닫아도 예외가 throw될 수 있으므로 올바른 순서로 오류 예외를 catch하는 것뿐만 아니라 catch 블록에서 호출에 사용된 채널을 중단하는 것도 중요합니다.

작업별 오류 정보가 제공되고 다른 작업에서 이 정보를 사용할 수 있으면 드물긴 하지만 채널을 중단하지 않아도 됩니다. 다른 모든 경우에는 채널을 중단하는 것이 좋습니다. 이러한 모든 사항을 보여 주는 샘플은 예상되는 예외 사항을 참조하세요.

다음 코드 예제에서는 선언된 오류와 선언되지 않은 오류를 비롯하여 기본 클라이언트 애플리케이션에서 SOAP 오류 예외를 처리하는 방법을 보여 줍니다.

참고 항목

이 샘플 코드에서는 using 구문을 사용하지 않습니다. 채널을 닫으면 예외가 throw될 수 있으므로 애플리케이션에서 먼저 WCF 클라이언트를 만든 다음 동일한 try 블록에서 WCF 클라이언트를 열고 사용하고 닫는 것이 좋습니다. 자세한 내용은 WCF 클라이언트 개요닫기 및 중단을 사용하여 WCF 클라이언트 리소스 해제를 참조하세요.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

참고 항목