2009-05-01 4 views
9

클라이언트 서버 시스템에 WCF를 사용합니다. 서버의 IService에 서비스 참조를 추가하면 ServiceClient 프록시 클래스가 생성됩니다. 내 코드처럼 보이는 다음WCF에서 클라이언트 클래스 재사용 후 오류 발생

ServiceClient client = new ServiceClient(); 
try 
{ 
    client.Operation1(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 
try 
{ 
    client.Operation2(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 

문제는 첫 번째 호출에서 통신 예외가있는 경우, 클라이언트의 상태 폴트 변경, 나는 그것이를 만들기 위해 다시하는 방법을 모르는 것입니다 두 번째 전화. 다시 열 수있는 방법이 있습니까? 또는 새 인스턴스를 만들어 인스턴스를 대체해야합니까 (우아한 방식이 아닌 것 같습니까?)

답변

0

이는 서버 쪽에서 처리되지 않은 예외가 원인 일 가능성이 큽니다. 기본적으로 WCF 런타임은 서비스 인스턴스를 종료하고 처리되지 않은 예외가 발생했을 때 오류가 발생한 상태가되면 더 이상 해당 채널을 통해 통신 할 수 없습니다. 따라서 서비스와의 새로운 세션을 만들어야합니다. 서버 측에서 예외를 catch하고 FaultException을 발생 시키거나 FaultContract를 정의하여 비누 오류를 보내야합니다. 또한 사용할 수있는 returnUnknownExceptionsAsFaults 서비스 비헤이비어가 있습니다.

16

ICommunicationObject (WCF 클라이언트 개체)가 오류 상태 인 경우이를 다시 열 수있는 유일한 방법은 새 개체를 만드는 것입니다. 장애가 발생한 상태의 원인이되는 첫 번째 통화에 통신 예외가있는 경우

ServiceClient client = new ServiceClient(); 
try 
{ 
    client.Operation1(); 
} 
catch(Exception ex) 
{ 
    if (client.State == CommunicationState.Faulted) 
    { 
      client.Abort(); 
      client = new ServiceClient(); 
    } 
} 
try 
{ 
    client.Operation2(); 
} 
catch(Exception ex) 
{ 
    // Handle Exception 
} 
+0

문제는 서비스 프록시에서 함수에 대한 대리자를 가져 오는 내부 함수가 있고 통신 예외가 throw되지 않을 때까지 함수를 반복적으로 실행한다는 것입니다 (자동 재 연결 구현). 따라서이 솔루션에서 함수는 각 실행 시도에 대한 프록시의 인스턴스를 만들고 호출자에게 업데이트 된 인스턴스를 반환해야하므로 닫힌 프록시를 보유하지는 않습니다 ... 추종 : -/ – Andy

5

, 당신은 기본적으로 WCF 클라이언트 프록시를 "다시 작성"해야합니다. 귀하의 예제에서 나는 아마도 다음과 같은 것을 할 것입니다 :

이렇게하면 장애가 발생한 경우 연결을 "다시 열 수 있습니다". 그것은 약간의 과잉을 보이지만, 클라이언트 측에 통신 예외를 받고 있다면, 아마 다른 뭔가에 가고있을 수 있습니다 (예 :? 서버 죽은 서버가 응답하지)

행운

3

에 동의 마지막 대답은, 일단 실패하면, 당신은 중단해야합니다.

public static void Use<TServiceInterface>(TServiceInterface proxy, Action handler) 
    { 
    Type proxyType = typeof(TServiceInterface); 
    IClientChannel channel = (IClientChannel)proxy; 

    try 
    { 
     handler(); 

     _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name)); 

     channel.Close(); 

     _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name)); 
    } 
    catch 
    { 
     if (channel.State == CommunicationState.Faulted) 
     { 
      _logSource.Log(LogLevel.Debug, string.Format("Aborting client channel for '{0}' ...", proxyType.Name)); 

      channel.Abort(); 

      _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' aborted.", proxyType.Name)); 
     } 
     else 
     { 
      _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name)); 

      channel.Close(); 

      _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name)); 
     } 

     throw; 
    } 
    } 

이가 그물에 이미 해결책의 약간의 수정이지만, 프록시를 처리하기위한 좋은 작품 : 우리는이 작업을 수행하려면 다음과 같이 람다의 조합 방법을 사용합니다. 그런 다음 동일한 람다 표현식에 여러 서비스 호출을 넣고 메소드에 전달할 수 있습니다.

+1

제공 한 솔루션에서 처음 사용하면 채널을 닫고 세션을 사용하면 성능이 좋지 않거나 기능이 잘못 될 수 있습니다. 또한 채널을 생성하지 않는 함수, 그것을 닫고있다. – Andy

+0

위의 메서드는 C#의 using 문과 같은 역할을합니다. 핸들러 액션이 실행 된 후에 close를 호출하는 것이 맞지만 핸들러 액션에 무한 수의 명령문이있을 수 있다고 생각합니다. 원한다면 서비스 인터페이스에 15 번 통화 할 수 있습니다. 또한 함수가 모든 것을 수행하지 않는다는 것이 이상하다고 생각하지 않습니다. 객체의 생성과 소멸을 별도의 메소드 나 별도의 코드 세그먼트로 분리하는 것은 매우 일반적입니다. 팩토리는 일반적으로 생성 한 객체를 정리하는 책임을지지 않습니다. –

관련 문제