使用 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 class。
我正在处理两种情况以确定应实例化哪个 IService:
- 在应用程序启动时,会设置一个标志,用于确定在注册之前要使用的服务(对于类似的设置,但不是针对相同的依赖树)。
- 在 "DoSomething" 方法的执行过程中,会决定应该使用这两个服务中的哪一个,所以我猜应该注册某种工厂并将其注入 "SomeClass" .
所以问题是我需要更改什么或添加到依赖项注册过程以及如何使用 ActivatorUtilities class 来实现这些目标?
谢谢。
不太清楚你想要达到的目标,但我认为它是这样的?
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));
如果 condition1 和 condition2 在依赖项注册时已知,换句话说在应用程序启动之前已提出请求。
对于另一种情况,在应用程序 运行 并且已发出请求之前,情况未知,因为内置的 .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);
}
}
}
这里唯一要记住的是,可以而且应该在定义所有其他应用程序接口的地方定义接口,并且您不要想要由于使用了 IServiceProvider 接口,因此应用程序的其余部分将与 MicrosoftExtensions.DependencyInjection 包紧密耦合,因此工厂的实现应该在定义其余注册逻辑的任何地方。
我非常努力地寻找 ActivatorUtilities.CreateFactory 方法的示例,该方法会给我类似的东西,但找不到。我希望这对某人有用。
我正在使用内置的 .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 class。
我正在处理两种情况以确定应实例化哪个 IService:
- 在应用程序启动时,会设置一个标志,用于确定在注册之前要使用的服务(对于类似的设置,但不是针对相同的依赖树)。
- 在 "DoSomething" 方法的执行过程中,会决定应该使用这两个服务中的哪一个,所以我猜应该注册某种工厂并将其注入 "SomeClass" .
所以问题是我需要更改什么或添加到依赖项注册过程以及如何使用 ActivatorUtilities class 来实现这些目标?
谢谢。
不太清楚你想要达到的目标,但我认为它是这样的?
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));
如果 condition1 和 condition2 在依赖项注册时已知,换句话说在应用程序启动之前已提出请求。
对于另一种情况,在应用程序 运行 并且已发出请求之前,情况未知,因为内置的 .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);
}
}
}
这里唯一要记住的是,可以而且应该在定义所有其他应用程序接口的地方定义接口,并且您不要想要由于使用了 IServiceProvider 接口,因此应用程序的其余部分将与 MicrosoftExtensions.DependencyInjection 包紧密耦合,因此工厂的实现应该在定义其余注册逻辑的任何地方。
我非常努力地寻找 ActivatorUtilities.CreateFactory 方法的示例,该方法会给我类似的东西,但找不到。我希望这对某人有用。