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

塞尔吉奥·罗梅罗(Sergio Romero)

我正在使用内置的.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类实现这些目标?

谢谢。

塞尔吉奥·罗梅罗(Sergio Romero)

因此,最棘手的部分是找出已经进行注册的第一种情况的处理方法,事实证明,有一种方法可以替换特定的定义。这可以通过以下代码完成:

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

在依赖项注册时知道condition1condition2时(换句话说,在发出任何请求之前在应用程序启动时),这非常好用

对于其他情况,直到应用程序运行并发出请求之前,情况才为人所知,因为内置的.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方法的示例非常努力,该方法会给我类似的东西,但找不到。我希望这对某人有用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章