Search code examples
c#wcfuwpfaultexceptionrealproxy

Throwing WCF Fault Exception from RealProxy of Service Contract


I have a C# application with a WCF backend and a UWP frontend. I have a service implementing my service contract. Everything works as expected if I catch exceptions on the services and re-throw them as Fault Exceptions.

Now I'm trying to clean up my service code by wrapping the service call using an instance of RealProxy and throwing my Fault Exceptions from the proxy. Unfortunately, now when an exception is thrown on the service, my client receives an exception with the following message:

"The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error."

I have the following Service Contract:

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

With the following implementation:

[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));
    }
}

My WCF service host has the following configuration with corresponding configuration on the client side.

<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>

Now, I've created a proxy:

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);
            }
        }
    }

(Thanks to @bradmo for the idea.)

Dynamically creating a proxy class

I'm using the proxy as my service:

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();
     }
  }
}

Throwing Fault Exceptions without the proxy works fine and the proxy works fine when there are no exceptions but when I use the proxy to wrap an exception, I get the following error on the client side:

"The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error."


Solution

  • The problem appears to be with the way your FaultContract is defined.

    Try doing something along these lines and see if it helps:

    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));
        }
    }
    

    Also: You should not wrap your serviceHost around a 'using' clause .. you're just asking for major trouble. Consider doing something like this:

            ServiceHost host = new ServiceHost(proxy);
            host.Open();
            Console.WriteLine("Running...");
            Console.ReadLine();
    
            try
            {
                host.Close();
            }
            catch
            {
                host.Abort();
            }