2017-03-23 2 views
0

Ich habe eine alte .NET-Anwendung, die Ninject verwendet, um eine Instanz eines ICommandHandler aufzulösen, wie unten gezeigt. Ich verwende auch den DB-Kontext, um SaveChanges() aufzurufen. Ich versuche jetzt, diesen Code zu konvertieren, damit ich ihn in einer neuen .NET Core-Anwendung mit seiner integrierten Abhängigkeitsinjektion verwenden kann.Ersetzen Sie Ninject durch .NET Core integrierte DI mit typisierten Parametern

public class CommandInvoker : ICommandInvoker 
    { 
     private readonly IKernel _kernel; 
     private readonly IArhomaContext _context; 

     public CommandInvoker(IKernel kernel, IArhomaContext context) 
     { 
      _kernel = kernel; 
      _context = context; 
     } 

     public void Execute<T>(T command) 
     { 
      var handler = _kernel.TryGet<ICommandHandler<T>>(); 
      handler.Handle(command); 
      _context.SaveChanges(); 
     } 
    } 

Ich denke, dass ich folgendes an die ConfigureServices Methode in Startup.cs hinzufügen:

services.AddScoped<ICommandHandler, CommandHandler>(); 

Aber ICommandHandler hat eine typisierte Parameter. Wie wird das gemacht oder registriert?

Zweitens muss ich es auflösen, um einen Handler zu erstellen, der den Befehl ausführt. Wie löst man das in .NET Core?

P.S. Ich möchte Ninject nicht weiter in meiner .NET Core App verwenden.

+3

'' 'services.AddScoped (typeof (ICommandHandler <>), typeof (CommandHandler <>));' '' –

+0

Danke Luke aber wie löse ich es? In Ninject gibt es den Kernel.TryGet <>, aber wie wird das in Core gemacht? – Ray

+1

Wahrscheinlich verwenden Sie die Stapelregistrierungsfunktion von Ninject, um alle Ihre Befehlshandler mit einem Aufruf zu registrieren. Dies ist etwas, das der Microsoft-Container nicht hat. Dies ist etwas, das Sie selbst erstellen müssen, oder Sie müssen ein Drittanbieter-Tool verwenden, das dies über den .NET Core-Container tun kann. Beachten Sie, dass in .NET Core viele Funktionen fehlen, die für Ihre Anwendung wichtig sein könnten. Die Umstellung auf diese sehr einfache DI-Implementierung liefert möglicherweise nicht immer die besten Ergebnisse. – Steven

Antwort

0

auf der Grundlage der Antwort LukeHutton gab, Gebrauch zu registrieren:

services.AddScoped(typeof(ICommandHandler<>), typeof(CommandHandler<>)); 

zu beheben:

// You should only Build the provider once in your code, to do so: 
var provider = services.BuilderServiceProvider(); //to protect against runtime injection, which is an anti-pattern 

// to Get an Actual ICommandHandler 
var commandHandler = services.GetService<ICommandHandler<MyT>>(); 
0

ich durch das gleiche Problem gehe, und ich erstellt eine Ereignisstruktur Umgang mit diesen Probleme zu lösen auf Asp.NET Core 2.0. ich ein Ereignis registrator erstellt, die die Event-Handler mapps:

public class EventRegistrator : IEventRegistrator 
{ 
    private readonly IDictionary<Type, IList<Type>> dictionary = new Dictionary<Type, IList<Type>>(); 

    public IEventRegistrator Add<Event, Handler>() 
     where Event : IEvent 
     where Handler : IEventHandler<Event> 
    { 
     var eventType = typeof(Event); 
     var handlerType = typeof(Handler); 

     if (!dictionary.ContainsKey(eventType)) 
     { 
      dictionary[eventType] = new List<Type>(); 
     } 

     dictionary[eventType].Add(handlerType); 

     return this; 
    } 

    public IEnumerable<Type> GetHandlers<Event>() 
     where Event : IEvent 
    { 
     if (dictionary.TryGetValue(typeof(Event), out IList<Type> handlers)) 
     { 
      return handlers; 
     } 

     return new List<Type>(); 
    } 

    public IEnumerable<Type> GetHandlers() 
    { 
     foreach (var item in dictionary) 
     { 
      foreach (var handler in item.Value) 
      { 
       yield return handler; 
      } 
     } 
    } 
} 

Die folgende codiert würde den Start hinzugefügt:

var registrator = new EventRegistrator() 
     .Add<TrainerCreatedEvent, ProcessionalWelcomeMessageHandler>() 
     .Add<TrainerCreatedEvent, ProfessionalCreatedCertificationStartHandler>(); 

services.AddSingleton<IEventRegistrator>(context => 
{ 
    return registrator; // All Event Handlers should be handled here 
}); 

foreach (var handler in registrator.GetHandlers()) 
{ 
    services.AddTransient(handler); 
} 

Dann wird der Vermittler (die Objekte, die das Ereignis versenden oder erhöhen):

public class SimpleMediator : IMediator 
{ 
    private readonly IServiceProvider provider; 
    private readonly IEventRegistrator registrator; 

    public SimpleMediator(IEventRegistrator registrator, IServiceProvider provider) 
    { 
     this.registrator = registrator; 
     this.provider = provider; 
    } 

    public async Task Dispatch<T>(T target) 
     where T : IEvent 
    { 
     var handlers = registrator.GetHandlers<T>(); 
     if (handlers == null) return; 

     foreach (Type item in handlers) 
     { 
      var instance = (IEventHandler<T>)provider.GetService(item); 
      if (instance == null) throw new NullReferenceException($"No type {item.ToString()} has been registred on the service collections. Add this type to the service collections."); 

      await instance.HandleAsync(target); 
     } 
    } 
} 

Die fehlenden Schnittstellen:

public interface IMediator 
{ 
    Task Dispatch<T>(T target) 
     where T : IEvent; 
} 


public interface IEventRegistrator 
{ 
    /// <summary> 
    /// Register a handler to the event. Multiple handlers are supported 
    /// </summary> 
    IEventRegistrator Add<Event, Handler>() 
     where Event : IEvent 
     where Handler : IEventHandler<Event>; 

    /// <summary> 
    /// Returns all handlers to a event 
    /// </summary> 
    IEnumerable<Type> GetHandlers<Event>() where Event : IEvent; 

    /// <summary> 
    /// Returns all handlers of all registered events. 
    /// </summary> 
    IEnumerable<Type> GetHandlers(); 
} 
Verwandte Themen