WCF FaultException IErrorHandler - не возвращается клиенту и вызывает исключение тайм-аута

Я пытаюсь реализовать IErrorHandler в службах WCF, которые используют iis и net.tcp.

Я установил сценарий, чтобы бросить DivideByZeroException на сервере. IErrorHandler запускается, как и ожидалось.

FaultException не возвращается клиенту, и я получаю исключение тайм-аута. Я не мог найти информацию / исключение в журнале событий.

Вот демонстрационный код. http://www.fileswap.com/dl/gQFlVsZK7M/ (Пожалуйста, нажмите на медленную загрузку изображения)

РЕДАКТИРОВАТЬ 1 (добавлен код из архива для всех, чтобы увидеть его):

Контракт на обслуживание:

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [FaultContract(typeof(DivideByZeroException))]
    string GetData(int value);

    [OperationContract]
    [FaultContract(typeof(DivideByZeroException))]
    CompositeType GetDataUsingDataContract(CompositeType composite);

    // TODO: Add your service operations here
}

Внедрение сервиса:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        int i = 0;

        //division by zero!
        int y = 10/i;
        return string.Format("You entered: {0}", value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}

Реализация IErrorHandler:

public class WcfErrorHandler : IErrorHandler
{
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        var v = error as DivideByZeroException;
        if (v != null)
            fault = Message.CreateMessage(
                version,
                new FaultException<DivideByZeroException>(v, new FaultReason(v.Message)).CreateMessageFault(),
                "http://the.fault.action");
    }

    public bool HandleError(Exception error)
    {
        return true;
    }
}

1 ответ

Решение

Ваша ServiceReference в ConsoleApplication1 не обновляется и не содержит атрибут контракта ошибки. Поскольку вы используете.NET для службы и клиента, лучше делить DataContract и ServiceContract между ними.

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

  1. app.config в ConsoleApplication1:

    <client>
    
      <endpoint address="net.tcp://localhost/WcfService1/Service1.svc"
        binding="netTcpBinding"
        contract="WcfService1.IService1" name="NetTcpBinding_IService2">
      </endpoint>
    
    </client>
    
  2. Код клиента:

    try
    {
        var fact = new ChannelFactory<WcfService1.IService1>("NetTcpBinding_IService2");
        var proxy = fact.CreateChannel();
        var ves = proxy.GetData(1);
        Console.WriteLine(ves);
    
    }
    catch (FaultException<DivideByZeroException> exp)
    {
        Console.WriteLine(exp.Detail);
    }
    
  3. Сервисный код (я предпочитаю перехватывать исключение как можно ближе к коду, вызывающему его, а затем выдает конкретное исключение ошибки):

    public string GetData(int value)
    {            
        try
        {
            int i = 0;
            int y = 10/i;
            return string.Format("You entered: {0}", value);
        }
        catch (DivideByZeroException d)
        {
            throw new FaultException<DivideByZeroException>(d);
        }
    }
    
  4. Ваш IErrorHandler:

    public class WcfErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
    
            if (error is FaultException)
            {
                //do nothing as it's already FaultException
                //you should do a transformation only in the case it's required
            }
            else
            {
                // Generate fault message manually including the exception as the fault detail
                MessageFault messageFault = MessageFault.CreateFault(
                    new FaultCode("Sender"),
                    new FaultReason(error.Message),
                    error);
                fault = Message.CreateMessage(version, messageFault, null);
            }
        }
    
        public bool HandleError(Exception error)
        {
            //here you can log an exception
            return true;
        }
    }
    

PS Кажется, вы неправильно разместили свой сервис. Чтобы проверить это, я сослался на WcfService1 в ConsoleApplication1. И сделал следующее:

  1. Добавлены такие строки в app.config ConsoleApplication1:

    <services>
      <service name="WcfService1.Service1" behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address="" binding="netTcpBinding" contract="WcfService1.IService1" />
        <!--<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> -->
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost/WcfService1/Service1.svc"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="True" />
          <errorHandler />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <extensions>
      <behaviorExtensions>
        <add name="errorHandler" type="WcfService1.ErrorHandlerExtension, WcfService1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    
  2. И прежде чем звонить в сервис клиенту, я запустил сервис:

    private static void Main(string[] args)
    {
       var host = new ServiceHost(typeof(WcfService1.Service1));
       host.Open();
       ... 
    
Другие вопросы по тегам