简体   繁体   中英

Replace Ninject with .NET Core built-in DI with typed parameters

I have an old .NET application that uses Ninject to resolve an instance of an ICommandHandler as shown below. I also uses the Db context to call SaveChanges(). I'm now trying to convert this code so that I can use it in a new .NET Core application with its built-in Dependency Injection.

    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();
        }
    }

I'm thinking that I have to add the following to the ConfigureServices method in Startup.cs:

services.AddScoped<ICommandHandler, CommandHandler>();

But ICommandHandler has a typed parameter. How is that done or registered?

Secondly, I need to resolve it to create a handler that executes the command. How does one resolve this in .NET Core?

PS I do not want to continue using Ninject in my .NET Core app.

based on the answer LukeHutton gave, to register use:

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

To resolve:

// 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>>();

I went through the same issue, and I created some event handling structure to solve this issues on Asp.NET Core 2.0. I created a event registrator that mapps the event handlers :

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;
            }
        }
    }
}

The following coded would be added to the startup :

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

Then the mediator ( the objects that dispatch or raise the event ) :

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

The missing interfaces :

    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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM