简体   繁体   English

使用带有类型化参数的.NET Core内置DI替换Ninject

[英]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. 我有一个旧的.NET应用程序,该应用程序使用Ninject解析ICommandHandler的实例,如下所示。 I also uses the Db context to call SaveChanges(). 我还使用Db上下文调用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. 我现在正在尝试转换此代码,以便可以在具有内置依赖关系注入的新.NET Core应用程序中使用它。

    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: 我在想我必须在Startup.cs的ConfigureServices方法中添加以下内容:

services.AddScoped<ICommandHandler, CommandHandler>();

But ICommandHandler has a typed parameter. 但是ICommandHandler具有类型化的参数。 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? 如何在.NET Core中解决此问题?

PS I do not want to continue using Ninject in my .NET Core app. PS我不想在我的.NET Core应用程序中继续使用Ninject。

based on the answer LukeHutton gave, to register use: 根据LukeHutton给出的答案,进行注册使用:

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. 我经历了同样的问题,并创建了一些事件处理结构来解决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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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