2017-02-07 8 views
1

WCF 백엔드와 UWP 프론트 엔드가있는 C# 응용 프로그램이 있습니다. 서비스 계약을 이행하고 있습니다. 서비스에서 예외를 잡아 오류 예외로 다시 던지면 모든 것이 예상대로 작동합니다.RealProxy of Service 계약에서 WCF 오류 예외가 발생했습니다.

이제 RealProxy 인스턴스를 사용하여 서비스 호출을 래핑하고 내 오류 예외를 프록시에서 throw하여 서비스 코드를 정리하려고합니다. 아쉽게도 서비스에 예외가 발생하면 클라이언트가 다음 메시지와 함께 예외를 수신합니다.

"서버가 의미있는 응답을 제공하지 않았습니다. 계약 불일치, 세션 종료 또는 내부 서버 오류. " 다음 구현

[ServiceContract(Namespace = @"blah/blah/blah", SessionModel = SessionMode.Required) 
public interface IService1 
{ 
    [OperationContract] 
    [FaultContract(typeof(Exception))] 
    bool DoSomething(Setting setting); 
} 

:

나는 다음과 같은 서비스 계약을

[Export(typeof(IService1)] 
[ServiceBehavior(InstanceContextMode = IntanceContextMode.Single, 
    ConcurrencyMode = ConcurrencyModel.Single] 
public class Service1 : IService1 
{ 
    bool DoSomthing(Setting setting) 
    { 
     try 
     { 
      throw new ArgumentException("setting"); 
     } 
     catch (Exception ex) 
     { 
      throw WrapException(ex); 
     } 
    } 

    private FaultException<Exception> WrapException(Exception ex) 
    { 
     string message = exception.GetBaseException().Message; 
     Console.WriteLine(string.Format("Exception: {0}", message)); 
     return new FaultException<Exception>(exception, new FaultReason(message)); 
    } 
} 

내 WCF 서비스 호스트가 클라이언트 측에서 구성을 해당 다음과 같은 구성을 가지고있다.

<system.serviceModel> 
    <services> 
     <service name="Host.Services.Service1"> 
     <endpoint address="net.tcp://localhost:8082/Service1" 
      binding="netTcpBinding" 
      contract="Host.Domain.IService1"/> 
     </service> 
    </services> 
    <bindings> 
     <netTcpBinding> 
     <binding maxReceivedMessageSize="1000000"> 
      <security mode="None"></security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    </system.serviceModel> 

지금, 나는 프록시 만들었습니다. (감사 아이디어를 @bradmo하는)

public class ServiceProxy<T> : RealProxy 
    { 
     private readonly T _instance; 

     private ServiceProxy(T instance) 
     : base(typeof(T)) 
     { 
      _instance = instance; 
     } 

     public static T Create(T instance) 
     { 
      return (T) new ServiceProxy<T>(instance).GetTransparentProxy(); 
     } 

     public override IMessage Invoke(IMessage msg) 
     { 
      var methodCall = (IMethodCallMessage) msg; 
      var method = (MethodInfo) methodCall.MethodBase; 

      try 
      { 
       var result = method.Invoke(_instance, methodCall.InArgs); 
       return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
      } 
      catch (Exception ex) 
      { 
       string message = ex.GetBaseException().Message; 
       Console.WriteLine(string.Format("Exception: {0}", message)); 
       var wrapped = new FaultException<Exception>(ex, new FaultReason(message)); 

       return new ReturnMessage(wrapped, msg as IMethodCallMessage); 
      } 
     } 
    } 

Dynamically creating a proxy class

나뿐만 프록시를 사용하고 내 서비스 :

static void Main(string[] args) 
{ 
    try 
    { 
     var service = new Bootstrapper().Run().GetExport<IService1>().Value; 
     IService1 proxy = ServiceProxy<IService1>.Create(service); 

      using (var host = new ServiceHost(proxy)) 
      { 
       host.Open(); 
       Console.WriteLine("Running..."); 
       Console.ReadLine(); 
      } 
    } 
    catch (Exception ex) 
    { 
      Console.WriteLine(string.Format("Exception: {0}", ex.GetBaseException().Message)); 
      Console.ReadLine(); 
    } 
    } 
} 

프록시가없는 예외 예외가 제대로 작동하고 예외가 없지만 프록시를 사용하여 예외를 래핑 할 때 프록시가 올바르게 작동하면 클라이언트 측에서 다음 오류가 발생합니다.

"서버에서 제공하지 않았습니다. 의미있는 대답; 이것은 계약 불일치, 조기 세션 종료 또는 내부 서버 오류가 발생할 수 있습니다. "

답변

0

문제는 당신 FaultContract가 정의 된 방법을 것으로 보인다.

다음 행과 함께 무언가를 시도하고 있는지 그것은하는 데 도움이 :

public interface IService 
{ 
    [OperationContract] 
    [FaultContract(typeof(WrappedExceptionFault))] 
    bool DoSomething(string setting); 
} 

[DataContract] 
public class WrappedExceptionFault 
{ 
    [DataMember] 
    public string Message { get; set; } 
} 

public class Service : IService 
{ 
    public bool DoSomething(string setting) 
    { 
     try 
     { 
      throw new ArgumentException(setting); 
     } 
     catch (Exception ex) 
     { 
      throw WrapException(ex); 
     } 
    } 

    private FaultException<WrappedExceptionFault> WrapException(Exception ex) 
    { 
     string message = ex.GetBaseException().Message; 
     Console.WriteLine(string.Format("Exception: {0}", message)); 
     WrappedExceptionFault fault = new WrappedExceptionFault() 
     { 
      Message = message, 
     }; 

     return new FaultException<WrappedExceptionFault>(fault, new FaultReason(message)); 
    } 
} 

을 또한 : 당신은 '사용'절 주위에 당신의 ServiceHost를 감싸 안 .. 당신은 그냥 주요 문제에 대한 요구하고이 같은 일을 고려하십시오.

 ServiceHost host = new ServiceHost(proxy); 
     host.Open(); 
     Console.WriteLine("Running..."); 
     Console.ReadLine(); 

     try 
     { 
      host.Close(); 
     } 
     catch 
     { 
      host.Abort(); 
     } 
+0

답해 주셔서 감사합니다. 서비스 호스트를'사용 '으로 감싸는 것이 왜 안 좋은가? –

+0

웹 페이지에는 웹에 많은 문서가 있습니다. 그 이유를 설명하는 몇 가지 기사가 있습니다. https://philmunro.wordpress.com/2011/03/07/wcf-using-gotcha/ && https://msdn.microsoft.com/en-us/library/aa355056 (v = vs.110) .aspx –

+0

트릭을 완료했습니다. 감사. –