繁体   English   中英

使用 ActivatorUtilities 确定在运行时注入哪个实现

[英]Use the ActivatorUtilities to determine which implementation to inject at runtime

我正在使用内置的 .Net Core IoC 容器来解决应用程序的依赖关系。 我配置它的方式如下,使用 Scrutor 扫描我的程序集:

services.Scan(s => s
    .FromAssembliesOf(currentAssemblyTypesList)
    .AddClasses(false)
    .UsingRegistrationStrategy(RegistrationStrategy.Append)
    .AsImplementedInterfaces()
    .WithTransientLifetime());

到目前为止,我已经有了一些简单的情况,其中每个接口都由一个依赖项实现,因此以前的配置可以完美地解决整个依赖项树。

现在考虑以下代码:

public interface IService {}  

public class ServiceOne : IService 
{
     public ServiceOne(IDependency dependency) {}
}  

public class ServiceTwo : IService 
{
     public ServiceTwo(IDependency dependency) {}
}  

public class SomeClass  
{  
    public SomeClass(IService service) {}  

    public void DoSomething()
    {
        this.service.SomeMethod();
    }
}

在这种情况下,“SomeClass”位于依赖树的中间,我有两个实现相同接口的服务,并且直到运行时才知道应该将哪个服务注入到“SomeClass”中。 出于不重要的原因,我被要求为此使用 ActivatorUtilities 类。

我正在处理两种确定应该实例化哪个 IService 的场景:

  1. 在应用程序启动时,设置一个标志来确定在注册发生之前要使用哪个服务(对于类似的设置,但不是对于相同的依赖树)。
  2. 在“DoSomething”方法的执行过程中,会决定应该使用这两个服务中的哪一个,所以我猜应该注册某种工厂并将其注入“SomeClass”。

所以问题是我需要在依赖项注册过程中更改或添加什么,以及如何使用 ActivatorUtilities 类来实现这些目标?

谢谢你。

不太清楚您要实现的目标,但我认为它是这样的?

services.AddTransient<IService>(sp =>
{
    if (condition1 && condition2)
        ActivatorUtilities.CreateInstance<ServiceOne>(sp);
    else
        ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
});

因此,最棘手的部分是当注册已经发生并且事实证明有一种方法可以替换特定定义时,弄清楚如何处理第一种情况。 这可以通过以下代码完成:

Func<IServiceProvider, object> factoryMethod = sp =>
{
    if (condition1 && condition2)
    {
        return ActivatorUtilities.CreateInstance<ServiceOne>(sp);
    }
    else
    {
        return ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
    }
};

services.Replace(ServiceDescriptor.Describe(typeof(IService), factoryMethod, ServiceLifetime.Transient));

当在依赖关系注册时知道条件 1条件 2时,这非常有效,换句话说,在发出任何请求之前的应用程序启动时。

对于在应用程序运行并发出请求之前不知道条件的其他场景,因为内置的 .Net Core IoC 容器不像 Castle 或 Autofac 等其他容器那样功能丰富,一种方法是手动创建一个工厂方法对象,如下所示:

public interface IServiceFactory
{
    IService Get(MyObject myObject);
}

public class ServiceFactory : IServiceFactory
{
    private readonly IServiceProvider sp;

    public ServiceFactory(IServiceProvider sp)
    {
        this.sp = sp;
    }

    public IService Get(MyObject myObject)
    {
        if(myObject.SomeProperty == "whatever")
        {
            return ActivatorUtilities.CreateInstance<ServiceOne>(this.sp);
        }
        else
        {           
            return ActivatorUtilities.CreateInstance<ServiceTwo>(this.sp);
        }
    }
}

这里唯一要记住的是,可以而且应该在定义所有其余应用程序接口的任何地方定义接口,并且您希望应用程序的其余部分与MicrosoftExtensions.DependencyInjection包紧密耦合,因为IServiceProvider接口的使用,因此工厂的实现应该在定义注册逻辑的其余部分的任何地方。

我真的很难找到一个ActivatorUtilities.CreateFactory方法的例子,它会给我这样的东西,但找不到一个。 我希望这对某人有用。

暂无
暂无

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

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