2010-06-14 4 views
23

Habe auf IErrorHandler gelesen und möchte die Konfigurationsroute gehen. Also, ich habe das Folgende in einem Versuch gelesen, es zu implementieren.IErrorHandler scheint meine Fehler in WCF nicht zu behandeln .. irgendwelche Ideen?

MSDN

Keyvan Nayyeri blog about the type defintion

Rory Primrose Blog

Dies ist im Grunde nur das Msdn Beispiel in einer Klasse eingewickelt, die IErrorHandler und IServiceBehaviour erbt ... dann wird diese in dem Verlängerungselement gewickelt, die von BehaviourExtensionElement erbt angeblich erlauben Sie mir, das Element in die web.config hinzuzufügen. Was habe ich verpasst?

Ich habe es zu kompilieren und von den verschiedenen Fehlern, die ich behoben habe, scheint es, dass WCF tatsächlich den Fehlerhandler lädt. Mein Problem ist, dass die Ausnahme, die ich im Fehlerhandler zu werfen habe, nicht die Ausnahme erhält, die an sie übergeben wird.

Meine Service-Implementierung ruft einfach eine Methode für eine andere Klasse auf, die ArgumentOutOfRangeException auslöst - diese Ausnahme wird jedoch nie vom Handler verarbeitet.

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

Servicevertrag

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

Die Fehlerbehandler Klasse

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


    } 
} 

und das Verhalten Verlängerungselement

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

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

Antwort

43

Hier ist ein voll funktionierendes Beispiel:

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

und 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

vielen Dank, es hat so lange gedauert, bis ich mein Setup bei der Arbeit beantwortet habe. Dies funktionierte gut auf meinem Setup zu Hause. –

+0

Danke für das vollständige Beispiel. Das hat wie ein Zauber funktioniert! – Stewie

+0

Arbeitete für mich, obwohl Visual Studio beschwert "das Element Verhalten hat ungültige Kind Element errorhandler" - Ich ignoriere es einfach und zur Laufzeit funktioniert es. – BornToCode

1

Sie können sehen, ob web.config funktioniert und lädt, indem Sie dem ApplyDispatchBehavior einen Druck oder einen Haltepunkt hinzufügen und prüfen, ob dieser beim ersten Öffnen des Dienstes ausgedruckt wird. Also wird es geladen?

Ich würde auch einen Druck/Breakpoint bei ProvideFault hinzufügen.

+0

Die Haltepunkte werden nicht getroffen. Der einzige Haltepunkt, den ich erreichen kann, ist der Webservice selbst. –

Verwandte Themen