【问题标题】:Replace Ninject with .NET Core built-in DI with typed parameters将 Ninject 替换为带有类型参数的 .NET Core 内置 DI
【发布时间】:2017-03-23 02:44:51
【问题描述】:

我有一个旧的 .NET 应用程序,它使用 Ninject 来解析 ICommandHandler 的实例,如下所示。我还使用 Db 上下文来调用 SaveChanges()。我现在正在尝试转换此代码,以便可以在具有内置依赖注入的新 .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();
        }
    }

我在想我必须在 Startup.cs 中的 ConfigureServices 方法中添加以下内容:

services.AddScoped<ICommandHandler, CommandHandler>();

但是 ICommandHandler 有一个类型化的参数。这是如何完成或注册的?

其次,我需要解决它以创建一个执行命令的处理程序。如何在 .NET Core 中解决这个问题?

附:我不想继续在我的 .NET Core 应用中使用 Ninject。

【问题讨论】:

  • services.AddScoped(typeof(ICommandHandler&lt;&gt;), typeof(CommandHandler&lt;&gt;));
  • 谢谢卢克,但我该如何解决呢?在 Ninject 中有 kernel.TryGet,但是在 Core 中是如何完成的呢?
  • 您可能正在使用 Ninject 的批量注册功能通过一次调用注册所有命令处理程序。这是 Microsoft 容器所没有的。这是您必须自己构建的东西,或者您需要使用可以在 .NET Core 容器之上执行此操作的第 3 方工具。请注意,.NET Core 中缺少许多对您的应用程序可能很重要的功能。切换到这种非常简单的 DI 实现可能并不总是产生最好的结果。

标签: c# dependency-injection asp.net-core


【解决方案1】:

根据 LukeHutton 给出的回答,注册使用:

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

解决:

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

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我创建了一些事件处理结构来解决 Asp.NET Core 2.0 上的这个问题。 我创建了一个映射事件处理程序的事件注册器:

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

    以下代码将被添加到启动中:

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

    然后是中介(调度或引发事件的对象):

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

    缺少的接口:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 2021-03-04
      相关资源
      最近更新 更多