2010-06-14 5 views
23

Czytałem już na IErrorHandler i chcę przejść do konfiguracji. tak, czytałem, co następuje, próbując go zaimplementować.IErrorHandler nie wydaje się obsługiwać moje błędy w WCF .. żadnych pomysłów?

MSDN

Keyvan Nayyeri blog about the type defintion

Rory Primrose Blog

Jest to w zasadzie tylko przykład MSDN zawinięte w klasy, która dziedziczy IErrorHandler i IServiceBehaviour ... wtedy to jest zawinięte w element przedłużający, która dziedziczy z BehaviourExtensionElement rzekomo pozwala mi dodać element do pliku web.config. Co przegapiłem?

Mam go do kompilacji i od różnych błędów mam naprawione wydaje się, że WCF faktycznie ładowanie obsługi błędów. Mój problem polega na tym, że wyjątek, który rzuca mi na obsługę w procedurze obsługi błędów, nie powoduje przekazania do niego wyjątku.

Moja implementacja usługi po prostu wywołuje metodę na innej klasie, która zgłasza ArgumentOutOfRangeException - jednak ten wyjątek nigdy nie zostanie obsłużony przez program obsługi.

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

Umowa serwisowa

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

Klasa 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) 
    { 


    } 
} 

a zachowanie Rozszerzenie Element

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

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

Odpowiedz

43

Oto pełny przykład roboczych:

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

i 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> 
+0

dziękuję bardzo, przepraszam, że tak długo dla mnie, aby odpowiedzieć na moje ustawienia w pracy jest zrekompensowany. To działało dobrze na mojej konfiguracji w domu. –

+0

Dzięki za pełny przykład. To działało jak czar! – Stewie

+0

Pracowałem dla mnie, chociaż studio graficzne skarży się, że "zachowanie elementu ma nieprawidłową obsługę błędu elementu podrzędnego" - po prostu ignoruję i podczas działania działa. – BornToCode

1

Można sprawdzić, czy plik web.config działa i ładuje, dodając wydruk lub punkt przerwania do obiektu ApplyDispatchBehavior i sprawdzić, czy zostanie wydrukowany/trafiony podczas pierwszego uruchomienia usługi. Więc jest ładowany?

Dodałbym również print/breakpoint w ProvideFault.

+0

Wartości graniczne nie oberwać. jedynym punktem przerwania, jaki mogę uzyskać, jest sama usługa sieciowa. –