IErrorHandler, похоже, не обрабатывает мои ошибки в WCF ... есть идеи? - PullRequest
24 голосов
/ 14 июня 2010

Читал на IErrorHandler и хочу пойти по пути конфигурации.Итак, я прочитал следующее в попытке реализовать его.

MSDN

Блог Кейвана Найери об определении типа

Блог Рори Первоцвета

Это в основном просто пример msdn, обернутый в класс, который наследует IErrorHandler и IServiceBehaviour ... затем он обернут в элемент Extension, который наследует от BehaviourExtensionElement, чтобы якобы позволить мне добавить элемент в web.config.Что я пропустил?

Я получил его для компиляции, и из-за различных исправленных ошибок кажется, что WCF фактически загружает обработчик ошибок.Моя проблема заключается в том, что исключение, которое я выбрасываю для обработки в обработчике ошибок, не получает исключение, переданное ему.

Моя реализация службы просто вызывает метод другого класса, который выдает ArgumentOutOfRangeException - однако это исключение никогда не выполняетсяобрабатывается обработчиком.

Мой web.config

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="basic">
          <security mode="None" />                      
        </binding>
      </basicHttpBinding>
    </bindings>
    <extensions>
      <behaviorExtensions>
        <add name="customHttpBehavior"
             type="ErrorHandlerTest.ErrorHandlerElement, ErrorHandlerTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior name="exceptionHandlerBehaviour">          
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <customHttpBehavior />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="exceptionHandlerBehaviour" name="ErrorHandlerTest.Service1">
        <endpoint binding="basicHttpBinding" bindingConfiguration="basic" contract="ErrorHandlerTest.IService1" />
      </service>
    </services>

Сервисный контракт

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [FaultContract(typeof(GeneralInternalFault))]
    string GetData(int value);
}

Класс ErrorHandler

public class ErrorHandler : IErrorHandler , IServiceBehavior 
{
    public bool HandleError(Exception error)
    {
        Console.WriteLine("caught exception {0}:",error.Message );
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
       if (fault!=null )
       {
           if (error is ArgumentOutOfRangeException )
           {
               var fe = new FaultException<GeneralInternalFault>(new GeneralInternalFault("general internal fault."));
               MessageFault mf = fe.CreateMessageFault();

               fault = Message.CreateMessage(version, mf, fe.Action);

           }
           else
           {
               var fe = new FaultException<GeneralInternalFault>(new GeneralInternalFault(" the other general internal fault."));
               MessageFault mf = fe.CreateMessageFault();

               fault = Message.CreateMessage(version, mf, fe.Action);
           }
       }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandler = new ErrorHandler();
        foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
            if (channelDispatcher != null)
            {
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }


    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {


    }
}

ИЭлемент расширения поведения

    public class ErrorHandlerElement : BehaviorExtensionElement 
    {
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }

        public override Type BehaviorType
        {
            get { return typeof(ErrorHandler); }
        }
    }

Ответы [ 2 ]

44 голосов
/ 05 июля 2010

Вот полный рабочий пример:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [FaultContract(typeof(MyFault))]
    string GetData(int value);
}

[DataContract]
public class MyFault
{

}

public class Service1 : IService1
{
    public string GetData(int value)
    {
        throw new Exception("error");
    }
}

public class MyErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
    {
        var vfc = new MyFault();
        var fe = new FaultException<MyFault>(vfc);
        var fault = fe.CreateMessageFault();
        msg = Message.CreateMessage(version, fault, "http://ns");
    }
}

public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
    public override Type BehaviorType
    {
        get { return GetType(); }
    }

    protected override object CreateBehavior()
    {
        return this;
    }

    private IErrorHandler GetInstance()
    {
        return new MyErrorHandler();
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandlerInstance = GetInstance();
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(errorHandlerInstance);
        }
    }

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            if (endpoint.Contract.Name.Equals("IMetadataExchange") &&
                endpoint.Contract.Namespace.Equals("http://schemas.microsoft.com/2006/04/mex"))
                continue;

            foreach (OperationDescription description in endpoint.Contract.Operations)
            {
                if (description.Faults.Count == 0)
                {
                    throw new InvalidOperationException("FaultContractAttribute not found on this method");
                }
            }
        }
    }
}

и web.config:

<system.serviceModel>
  <services>
    <service name="ToDD.Service1">
      <endpoint address=""
                binding="basicHttpBinding"
                contract="ToDD.IService1" />
    </service>
  </services>

  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
        <errorHandler />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name="errorHandler"
            type="ToDD.ErrorHandlerExtension, ToDD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
  </extensions>

</system.serviceModel>
1 голос
/ 05 июля 2010

Вы можете увидеть, работает ли web.config и загружается ли, добавив печать или точку останова в ApplyDispatchBehavior, и посмотреть, будет ли она напечатана / нажата при первом открытии службы.Так загружается ли он?

Я бы добавил точку печати / останова и в ProvideFault.

...