2013-08-07 22 views
10

Sto implementando IErrorHandler per centralizzare tutta la gestione degli errori per il mio servizio WCF in un unico posto. Questo funziona abbastanza bene:Iniezione di dipendenze in un'implementazione di IErrorHandler

public class ServiceErrorHandler : IErrorHandler 
{ 

    public bool HandleError(Exception error) 
    { 
     // ..Log.. 
    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     // ..Provide fault.. 
    } 

} 

Ora, stiamo usando Ninject per iniettare le dipendenze nel resto del servizio, e mi piacerebbe fare lo stesso qui. Dal momento che WCF sta costruendo gli oggetti in base alla mia configurazione, e io non credo di avere nessun hook in questo processo, ho bisogno di utilizzare l'iniezione di proprietà:

[Inject] 
    public ILoggingService Logger { get; set; } 

Tuttavia, questo non sembra avere iniettato. Ho provato ad utilizzare le estensioni MVC di Ninject per impostare ServiceErrorHandler per consentire l'iniezione come un filtro, ma non sembra che faccia il trucco. C'è un modo per farlo accadere?

+0

Usi anche l'estensione di WCF Ninject? –

+0

@DanielMarbach: ho le estensioni WCF, ma non vedo nulla in esse che possa aiutare in questa situazione. C'è qualcosa che potrei usare? – zimdanen

+0

@zimdanen hai risolto questo problema? Il meglio sarebbe iniettare ILogger senza IoC, ma con puro ... DI puro. Basta iniettare un'interfaccia ILogger nel tuo 'ServiceErrorHandler' – Marshall

risposta

6

Risposta tardiva, ma è possibile iniettare le dipendenze in IErrorHandler creando la propria ServiceHost personalizzata, ad esempio TestServiceHost.

Nella tua TestServiceHost quello che devi fare:

  1. Implementare costruttore con IErrorHandler parametro.
  2. All'interno, creare una classe nidificata privata denominata ErrorHandlerBehaviour *, che deve implementare sia IServiceBehavior e IErrorHandler. Deve inoltre avere un costruttore con il parametro IErrorHandler.
  3. Override OnStarting() metodo, dove si aggiungerà ErrorHandlerBehaviour ai comportamenti di servizio. Tutti i comportamenti devono essere aggiunti prima dello base.OnStarting().

* l'idea è venuta dall'esempio di Juval Lowy nel libro "Programmazione servizi WCF". Maggiori informazioni sui guasti e le estensioni degli errori che puoi trovare lì.

Questa è l'applicazione della console host funzionante. Io non uso CIO lì, basta Pure DI, ma si può facilmente risolvere logger con qualsiasi CIO che si desidera:

using System; 
using System.Collections.ObjectModel; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 

namespace ConsoleHost 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var logger = new DummyLogger(); 
      var errorHandler = new TestErrorHandler(logger); 

      ServiceHost host = new TestServiceHost(errorHandler, typeof(TestService), new Uri("net.tcp://localhost:8002")); 
      host.Open(); 

      Console.WriteLine("Press enter to exit"); 
      Console.ReadKey(); 
     } 
    } 

    [ServiceContract] 
    public interface ITestService 
    { 
     [OperationContract] 
     string Test(int input); 
    } 

    public class TestService : ITestService 
    { 
     public string Test(int input) 
     { 
      throw new Exception("Test exception!"); 
     } 
    } 

    public class TestErrorHandler : IErrorHandler 
    { 
     private ILogger Logger { get; } 

     public TestErrorHandler(ILogger logger) 
     { 
      Logger = logger; 
     } 

     public bool HandleError(Exception error) 
     { 
      Logger.Log(error.Message); 
      return true; 
     } 

     public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
     { 
      FaultException fe = new FaultException(); 
      MessageFault message = fe.CreateMessageFault(); 
      fault = Message.CreateMessage(version, message, null); 
     } 
    } 

    public class TestServiceHost : ServiceHost 
    { 
     private readonly IErrorHandler errorHandler; 

     public TestServiceHost(IErrorHandler errorHandler, Type serviceType, params Uri[] baseAddresses) 
      : base(serviceType, baseAddresses) 
     { 
      this.errorHandler = errorHandler; 
     } 

     protected override void OnOpening() 
     { 
      Description.Behaviors.Add(new ErrorHandlerBehaviour(errorHandler)); 
      base.OnOpening(); 
     } 

     class ErrorHandlerBehaviour : IServiceBehavior, IErrorHandler 
     { 
      private readonly IErrorHandler errorHandler; 

      public ErrorHandlerBehaviour(IErrorHandler errorHandler) 
      { 
       this.errorHandler = errorHandler; 
      } 

      bool IErrorHandler.HandleError(Exception error) 
      { 
       return errorHandler.HandleError(error); 
      } 

      void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault) 
      { 
       errorHandler.ProvideFault(error, version, ref fault); 
      } 

      void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
      { 
       foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) 
       { 
        channelDispatcher.ErrorHandlers.Add(this); 
       } 
      } 

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

      void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
      { 
      } 
     } 
    } 

    // Dummy logger 
    public interface ILogger 
    { 
     void Log(string input); 
    } 

    public class DummyLogger : ILogger 
    { 
     public void Log(string input) => Console.WriteLine(input); 
    } 
} 

e la configurazione:

<system.serviceModel> 
    <services> 
    <service name="ConsoleHost.TestService"> 
     <endpoint address="net.tcp://localhost:8002/TestService" 
       binding="netTcpBinding" 
       contract="ConsoleHost.ITestService" /> 
    </service> 
    </services> 
</system.serviceModel> 

Btw. Assicurati di aver aggiunto System.Runtime.Serialization alle tue referenze

Problemi correlati