【问题标题】:Create instance using ctor injection and ServiceProvider使用 ctor 注入和 ServiceProvider 创建实例
【发布时间】:2018-01-27 02:15:50
【问题描述】:

我知道有IServiceCollection 接口可以注册我的服务,IServiceProvider 可以实例化服务。

如何根据指定的类型实例化一个使用注册服务的类?

class MyClass
{
    public MyClass(ISomeService someService) { }
}

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()

MyClass instance = CreateInstance(typeof(MyClass));

object CreateIntance(Type type)
{
   ???
}

例如,ASP.NET Core 如何创建控制器实例?

我已经简单地实现了激活器,但在 .NET Core 中还没有类似的东西吗?

private static object CreateInstance(Type type, IServiceProvider serviceProvider)
{
    var ctor = type.GetConstructors()
        .Where(c => c.IsPublic)
        .OrderByDescending(c => c.GetParameters().Length)
        .FirstOrDefault()
        ?? throw new InvalidOperationException($"No suitable contructor found on type '{type}'");

    var injectionServices = ctor.GetParameters()
        .Select(p => serviceProvider.GetRequiredService(p.ParameterType))
        .ToArray();

    return ctor.Invoke(injectionServices);
}

}

编辑:这是我的场景。我重构了一些实现这个接口的遗留代码。

public interface IEventDispatcher
{
    void RegisterHandler(Type handler);
    void Dispatch(DomainEvent @event);
}

在 Dispatch 方法实现中,我创建了处理程序的实例:

public class InMemoryBus : IEventDispatcher
{
    private readonly List<Type> _handlers = new List<Type>();
    private readonly Func<Type, object> activator;

    /// <param name="activator">Used to create instance of message handlers</param>
    public InMemoryBus(Func<Type, object> activator)
    {
        this.activator = activator;
    }

    public void Dispatch(DomainEvent @event)
    {
        Type messageType = message.GetType();
        var openInterface = typeof(IHandleMessages<>);
        var closedInterface = openInterface.MakeGenericType(messageType);

        var handlersToNotify = from h in _handlers
                               where closedInterface.GetTypeInfo().IsAssignableFrom(h.GetTypeInfo())
                               select h;
        foreach (Type h in _handlersToNotify)
        {
            //this is the tricky part
            var handlerInstance = activator(h);
            closedInterface.GetTypeInfo()
                .GetMethod(nameof(IHandleMessages<T>.Handle))
                .Invoke(handlerInstance, new[] { message });
        }
    }

    public void RegisterHandler(Type type) => _handlers.Add(type);
}

【问题讨论】:

  • DI 框架会为您完成这项工作,只需将参数传递给您的构造函数。
  • serviceProvider.GetService() 返回 null。在 CreateInstance(Type) 方法中我不知道编译时的参数是什么
  • 那么我们可能需要查看一些关于您如何注册所有服务的实际代码。
  • 这都是我的问题
  • 那你没有注册MyClass...

标签: c# dependency-injection .net-core inversion-of-control


【解决方案1】:

给定

public class MyClass {
    public MyClass(ISomeService someService) { 
        //...
    }
}

您需要构建整个对象图,以便提供者知道它可以创建什么

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()
serviceCollection.AddTransient<MyClass>();

IServiceProvider provider = serviceCollection.BuildServiceProvider();

MyClass instance = provider.GetService<MyClass>();

provider.GetService&lt;MyClass&gt;()被调用时,提供者将初始化MyCLass,解决进程中的所有依赖。

参考Introduction to Dependency Injection in ASP.NET Core

【讨论】:

  • 是的,我知道当我注册 MyClass 和服务时,我将能够解决它。但是我真的必须注册所有可能的课程吗?首先,MyClass 不是服务,所以我不确定它是否属于 ServiceCollection。其次,Asp.net 核心都没有将控制器注册到 ServiceCollection 中,但它会创建控制器的实例
  • @Liero,您看不到它何时注册控制器。并不意味着他们没有。当您调用AddMvc 时,它会反映所有控制器并将它们添加到集合中。 Github上的源代码去查看
  • @Liero 我想你误解了这里的 DI 上下文中的“服务”是什么。
  • @Liero 看看我在这里给出的答案stackoverflow.com/a/36549612/5233410
  • @Nkosi:我实际上已经检查过了。 IServiceProvider.GetService&lt;MyController&gt;() 返回 null 即使在一切都被引导之后,例如在请求期间。也许它在另一个范围内注册了
【解决方案2】:

https://stackoverflow.com/a/45756192/45091 是做事的正确方式。

例如,ASP.NET Core 如何创建控制器实例?

如果您不想注册服务,可以使用我们所说的“类型激活”。有一种名为 ActivatorUtilities 的类型具有您想要的辅助方法。你调用ActivatorUtilities.CreateInstance(serviceProvider, type),它会使用指定的服务提供商激活该类型。

【讨论】:

  • 有没有办法将ActivatorUtilities.CreateInstance(type, serviceProvider) 与混合参数一起使用,有些来自容器,有些来自您自己提供?
  • 是的,它有额外的参数
  • 有没有办法将 DI 类型解析和参数化实例激活结合起来?如果没有,我认为这可能是一个有用的功能:stackoverflow.com/q/69207420/1768303
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2017-07-02
相关资源
最近更新 更多