[英]ASP.NET Core option dependency in constructor
我正在使用ASP.NET Core,并且尝试创建一个具有可选参数的可解析类:
public class Foo
{
public Foo() : this(null)
{}
public Foo(IValidator<FooEntity> validator)
{
}
}
我为该对象创建了两个构造函数,因此,如果未找到依赖项,我将假定它会退回到默认构造函数。
但是,当我运行我的应用程序时,会出现此错误
附加信息:尝试激活“ Foo”时,无法解析类型为“ FluentValidation.IValidator`1 [FooEntity]”的服务
我知道可能有一种方法可以手动解决Foo对象的构造。 但是我不希望这样做,因为我必须为我创建的没有验证器的每个类都这样做。
没有人知道如何将ASP.NET Core DI配置为在找不到依赖项时回退到其他构造函数吗?
编辑
抱歉,我之前应该更清楚一点。
我实际上是在CRUD服务的基类中引用这个Foo类,该类将反复使用。
我正在寻找一种通用解决方案,该解决方案不需要我配置每次创建的每个服务。
因此,使用lambda来解决此问题不是一种选择,空对象模式似乎是可行的,但我无法理解如何编写通用的模式,而不必为每个服务进行配置
我认为容器的一般行为是使用最多的参数来解析构造函数。
基本上, AddTransient
作用如下:
services.AddTransient<Foo>();
//equals to:
services.AddTransient<Foo>(c=> new Foo(c.GetService<IValidator<FooEntity>()));
因此,您可以这样自己注册:
services.AddTransient<Foo>(c=> new Foo());
此时,在启动类中,您应该知道IValidator<FooEntity>
是否已注册。 或者,如果您使用反射,则将此逻辑添加到反射代码中。
这两个选项之间的区别在于,第一个选项是在启动时创建用于解析类的lambda function
。 +如果更改构造函数,则无需在其他地方更改代码。
如果您自己创建lambda,则该lambda是在构建时编译的,因此从理论上讲,启动速度应该更快(我尚未对此进行测试)。
最好的心态是拥有您正在使用的库。 在Visual Studio / Resharper中,您可以反编译源代码,或者现在可以在github上找到存储库。
在这里,您可以看到源代码,可以看到如何将services
参数“编译”到IServiceProvider(请参阅BuildServiceProvider()
方法,它将为您提供很多见识。)
还要看:
做到这一点的最好方法是,(抱歉伪代码,但我手边没有编辑器)。
getTypes()
.Where(x=> x.EndsWith("Entity") //lets get some types by logic
.Select(x=> typeof(IValidator<>).MakeGeneric(x)) //turn IValidator into IValidator<T>
.Where(x=> !services.IsRegistered(x))
.Each(x=> services.Add(x, c=> null)) //register value null for IValidator<T>
您需要先注册 IValidator<T>
:
var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
services.AddTransient<IValidator<FooEntity>, RealValidator<FooEntity>>();
services.AddTransient<Foo>();
var serviceProvider = services.BuildServiceProvider();
var validator = serviceProvider.GetService<IValidator<FooEntity>>();
var foo = serviceProvider.GetService<Foo>();
Assert.NotNull(validator);
Assert.NotNull(foo);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.