Создание исключения ошибки WCF из RealProxy контракта на обслуживание

У меня есть приложение C# с бэкэндом WCF и внешним интерфейсом UWP. У меня есть сервис, реализующий мой сервисный контракт. Все работает как положено, если я перехватываю исключения на сервисах и перекидываю их как Fault Exceptions.

Теперь я пытаюсь очистить свой сервисный код, обернув служебный вызов с использованием экземпляра RealProxy и выбросив мои исключения ошибок из прокси. К сожалению, теперь, когда в службе возникает исключение, мой клиент получает исключение со следующим сообщением:

"Сервер не предоставил значимого ответа; это может быть вызвано несоответствием контракта, преждевременным завершением сеанса или внутренней ошибкой сервера".

У меня есть следующий контракт на обслуживание:

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

Теперь я создал прокси:

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

(Спасибо @bradmo за идею.)

Динамическое создание прокси-класса

Я использую прокси в качестве своего сервиса:

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

Создание исключений ошибок без прокси-сервера работает нормально, и прокси-сервер работает нормально, когда нет исключений, но когда я использую прокси-сервер для переноса исключения, я получаю следующую ошибку на стороне клиента:

"Сервер не предоставил значимого ответа; это может быть вызвано несоответствием контракта, преждевременным завершением сеанса или внутренней ошибкой сервера".

1 ответ

Решение

Кажется, проблема в том, как определяется ваш 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();
        }
Другие вопросы по тегам