构造函数中的ASP.NET Core选项依赖项

时间:2017-02-14 07:45:14

标签: c# dependency-injection asp.net-core

我正在使用ASP.NET Core,而我正在尝试创建一个具有可选参数的可解析类:

public class Foo
{
     public Foo() : this(null)
     {}

     public Foo(IValidator<FooEntity> validator)
     {
     }
}

我为这个对象创建了两个构造函数,这样如果找不到依赖项,我会认为它只会回退到默认的构造函数。

然而,当我运行我的应用程序时,我收到此错误

  

其他信息:无法解决类型&#39; FluentValidation.IValidator`1 [FooEntity]&#39;在尝试激活&#39; Foo&#39;

我知道可能有办法手动解析Foo对象的构造。但我宁愿不这样做,因为我必须为没有验证器的每个班级做这个。

如果找不到依赖项,是否有人知道如何配置ASP.NET Core DI以回退到不同的构造函数?

修改

对不起,我之前应该更清楚一点。

这个Foo类我真正指的是一个CRUD服务的基类,它将被反复使用。

我正在寻找一个通用解决方案,它不需要我配置我每次创建的每个服务。

所以使用lambda来解决这个问题不是一个选择。空对象模式似乎可行,但我无法理解如何编写一个我不必为每个服务配置的通用模式< / p>

2 个答案:

答案 0 :(得分:3)

我认为Container的一般行为是用最多的参数来解析构造函数。

基本上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是在build上编译的,所以理论上启动应该更快(我没有测试过)。

伟大的心态

一个伟大的思维方式是拥有您正在使用的库。在Visual Studio / Resharper中,您可以反编译源代码,或者您现在可以在github上找到存储库。

在那里你可以看到源代码,你可以看到services参数是如何被编译的&#39;到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> 

答案 1 :(得分:1)

您需要先register 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);