构造函数中的ASP.NET Core选项依赖 [英] ASP.NET Core option dependency in constructor

查看:193
本文介绍了构造函数中的ASP.NET Core选项依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

public Foo(IValidator< FooEntity>验证器)
{
}
}

我为这个对象创建了两个构造函数,以便如果没有找到依赖关系,我会假设它只是回到默认构造函数。



但是当我运行我的应用程序时,我收到这个错误


附加信息:尝试激活Foo时无法解析FluentValidation.IValidator[FooEntity]类型的服务


我知道有可能手动解决Foo对象的构造。但是我不喜欢这样做,因为我必须为每个没有验证器的类创建一个类。



有没有人知道如何配置ASP.NET核心如果没有找到依赖关系,DI可以回到不同的构造函数?



编辑



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



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



所以使用lambda来解决这个不是一个选择,空对象模式似乎是可行的,但是我不能理解如何编写一个通用的模式,我将不必配置每个服务

解决方案

我认为它的一般行为是容器解析具有最多参数的构造函数。



基本上, AddTransient 的做法如下:

  services.AddTransient<富>(); 
//等于:
services.AddTransient< Foo>(c => new Foo(c.GetService< IValidator< FooEntity>()));

所以你可以这样注册:

  services.AddTransient< Foo>(c => new Foo()); 

在启动类中,您应该知道如果 IValidator&FooEntity> 已被注册。或者,如果您使用反射,将此逻辑添加到您的反射代码。



差异



2选项是第一个选项是在启动时创建解决该类的 lambda函数。如果你改变了构造函数,那么没有代码需要改变其他地方。



如果你自己创建这个lambda,那么这个lambda是在build上编译的,所以理论上应该是启动应该更快没有测试这个)。



伟大的心态



一个伟大的心态是拥有你正在使用的图书馆。在Visual studio / Resharper中,您可以反编译源代码,或者您可以在github上找到存储库。



可以看到源代码,你可以看到服务参数是编译到IServiceProvider(请参阅 BuildServiceProvider()方法,它会给你很多洞察力。 )



另见:





解决方案



最好这样做是(对不起psuedo代码,但我手头没有编辑者)。

  getTypes()
.Where(x => x.EndsWith(Entity)//让我们通过逻辑
.Select(x => typeof(IValidator))获取一些类型。MakeGeneric(x))//将IValidator转换成IValidator< T>
.Where(x =>!services.IsRegistered(x))
.Each(x => services.Add(x,c => null))//注册值null for IValidator< ; T>


I'm using ASP.NET Core and I'm attempting to create a resolvable class which has an optional parameter:

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

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

I've created two constructors for this object so that if a dependency isn't found, I would assume it would just fall back to the default constructor.

However when I run my application I receive this error

Additional information: Unable to resolve service for type 'FluentValidation.IValidator`1[FooEntity]' while attempting to activate 'Foo'

I know there is probably a way to manually resolve the construction of the Foo object. But I would prefer not to do that because I will have to do this for every class that I create without a validator.

Does anyone know how to configure ASP.NET Core DI to fall back to a different constructor if the dependency is not found?

EDIT

Sorry, I should of been a bit more clear before.

This Foo class I'm referring to in really a base class for a CRUD Service, which will be used over and over again.

I'm looking for a generic solution which doesn't require me to configure each Service I create each time.

So using a lambda to resolve this is not an option, The null object pattern seems feasible but I can't comprehend how to write a generic one in which I won't have to configure for each service

解决方案

I think its general behavior of Containers to resolve the constructor with the most parameters.

Basically what AddTransient does is the following:

services.AddTransient<Foo>();
//equals to:
services.AddTransient<Foo>(c=> new Foo(c.GetService<IValidator<FooEntity>()));

So you can register it yourself like this:

services.AddTransient<Foo>(c=> new Foo());

At this point in the startup class you should know if IValidator<FooEntity> has been registered. Or, if you are using reflection add this logic to your reflection code.

Difference

The difference between the 2 options is that with the first option is that the lambda function to resolve the class is created on startup. + if you change the constructor no code needs to be changed elsewhere.

If you create the lambda yourself this lambda is compiled on build, so theoretically startup should be faster (I have not tested this).

Great mindset

A great mindset is to own the libraries you are using. In Visual studio/Resharper you can decompile source-code, or you can find the repositories on github nowadays.

There you can see the source code, you can see how the services parameters is 'compiled' to the IServiceProvider (see BuildServiceProvider() method, it will give you alot of insight.)

Also look at:

Solution

best way to do it is this, (sorry for psuedo code but i have no editor at hand).

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> 

这篇关于构造函数中的ASP.NET Core选项依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆