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

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

Теперь я пытаюсь очистить свой служебный код, обернув вызов службы с помощью экземпляра 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();
     }
  }
}

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

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


person Connell.O'Donnell    schedule 07.02.2017    source источник


Ответы (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 предложение using ... вы просто требуете серьезных проблем. Попробуйте сделать что-то вроде этого:

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

        try
        {
            host.Close();
        }
        catch
        {
            host.Abort();
        }
person Jorge Del Conde    schedule 15.02.2017
comment
Спасибо за Ваш ответ. Почему плохо заключать хост службы в using? - person Connell.O'Donnell; 16.02.2017
comment
В сети есть много документации по этому поводу. Вот пара статей, объясняющих, почему: philmunro.wordpress.com/ 07.03.2011 / wcf-using-gotcha && msdn.microsoft.com/en-us/library/aa355056 (v = vs.110) .aspx - person Jorge Del Conde; 16.02.2017