ASP.NET Core DI构造函数与RequestServices [英] ASP.NET Core DI Constructor vs RequestServices

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

问题描述

为什么通过 HttpContext.RequestServices IServiceProvider 请求服务的做法不正确。我可以在各处阅读此语句:

Why is requesting services via HttpContext.RequestServices or IServiceProvider consider bad practise. I can read this statement all over the place:


建议使用构造函数注入而不是获取它
使用RequestServices。

It is recommended to use constructor injection instead of getting it using RequestServices.






我的想法正好相反。尽可能使用RequestServices。让我解释一下原因。
我想使控制器尽可能小,所以我创建了单独的服务。这样,我的控制器就很干净了:


My idea is just the opposite. Use RequestServices where ever possible. Let me explain why. I want to keep controllers as small as possible so I create separate services. This way, my controllers are clean:

public class MyController : Controller
{
    public MyController(IMyServices MyServices){}

    public async Task<IActionResult> GetSomething(int parameter)
    {
       return await this.MyServices.SomeMethod(parameter);
    }
}

所有服务均从base继承,其中包含管理逻辑权限,缓存sql请求...。

使用构造函数方法,我得到了一个非常复杂的调用基系统:

All services inherit from base, which contains logic for managing rights, caching sql requests ... .
With constructor approach I get very complicated system of calling base:

public class MyBaseService
{
    public MyBaseService(ILogger Logger, AppDbContext Context, IMemoryCache Cache) { }

    public bool HasRight(string right) { return true; }

    public bool IsLoggedIn() { return true; }
}

public class MyServices : MyBaseService
{
    public MyServices(ILogger Logger, AppDbContext Context, IMemoryCache Cache) : base(Logger, Context, Cache)
    {    
    }
}

GetRequiredService 我简化了基于构造函数的调用:

but with GetRequiredService I simplify calling base on constructor:

public class MyBaseService2
{
    private ServiceProvider _ServiceProvider;
    public MyBaseService2(IServiceProvider ServiceProvider)
    {

    }

    protected ILogger Logger { get { return this._ServiceProvider.GetRequiredService<ILogger>(); } }

    protected AppDbContext Context { get { return this._ServiceProvider.GetRequiredService<AppDbContext>(); } }

    protected IMemoryCache Cache { get { return this._ServiceProvider.GetRequiredService<IMemoryCache>(); } }

    public bool HasRight(string right) { return true; }

    public bool IsLoggedIn() { return true; }
}

public class MyServices2 : MyBaseService2
{
    public MyServices2(IServiceProvider ServiceProvider) : base(ServiceProvider)
    {    
    }
}

是的,BaseService包含更多代码,但是当我在BaseService中需要其他服务时,无需修复每个类的基本构造函数调用。同样,我所有的服务都具有更简单的构造函数(只是 IServiceProvider )。

Yes, BaseService contains more code, but when I need additional services in BaseService, there is no need to fix every class base constructor call. Also all my services have much simpler constructor (just IServiceProvider).

如果我反对构造函数方法。如果存在作用域,则对MyServices调用 ServiceProvider.GetRequiredService 是否会对性能造成任何影响。

If I go against constructor approach. Is there any performance hit if calling ServiceProvider.GetRequiredService for MyServices if there lifetime is Scoped.

推荐答案


为什么通过HttpContext请求服务。RequestServices或IServiceProvider认为是不好的做法。

Why is requesting services via HttpContext.RequestServices or IServiceProvider consider bad practise.

这是一种不好的做法,因为它是服务定位器反模式的实现

It's considered a bad practice because it is an implementation of the Service Locator anti-pattern.

您试图通过将许多常见的依赖关系和通用逻辑移入基类来使控制器类变小,但这是一种反模式本身,因为:

You are trying to keep your controller classes small by moving many common dependencies and common logic into the base class, but that is an anti-pattern by itself, because:


  • 即使从基类解析了依赖项,这些依赖项仍被隐藏,如这篇文章进行了说明。这意味着依赖项将从单元测试和DI容器中隐藏,后者将无法对对象图进行分析。

  • 将依赖项移至基类不会降低复杂性
  • 这会导致基类中充斥着许多职责,这将导致基类基本类违反单一责任原则。这可以迫使基类成为神类并在不断变化的情况下。

  • Even though dependencies are resolved from the base class, those dependencies are still hidden, as this article explains. This means dependencies are hidden from your unit tests and from the DI Container, who will be unable to do analysis on your object graphs.
  • Moving dependencies to the base class doesn't lower the complexity of a class, since the base class is always strongly coupled with the derivative.
  • It causes many responsibilities to be crammed into the base class, which will cause the base class to violate the Single Responsibility Principle. This can force the base class to become a god class and under constant change.

基类使用继承,而软件中的普遍共识发展是,您应该偏爱组成比继承

Base classes use inheritance, while the general consensus in software development is that you should favor Composition over inheritance.

由于您应该支持组合,因此这会自动导致依赖注入。如果没有基类,则立即发现违反单一责任原则的问题将变得更加容易,因为您的构造函数将获得更多的参数。再次注意,使用Service Locator时依赖项的数量不会改变,它们的计数更难。

Since you should favor composition, this automatically leads to Dependency Injection. Without having a base class, it immediately becomes easier to spot Single Responsibility Principle violations, because your constructors will get more arguments. Note again that the number of dependencies doesn't change when using Service Locator, they are just harder to count.

您应该接受一个事实,即构造函数注入容易导致< a href = https://blog.ploeh.dk/2010/01/20/RebuttalConstructorover-injectionanti-pattern/ rel = nofollow noreferrer>构造函数过度注入,因为这表明我们类太多了,这表明我们应该重新设计此类。

You should embrace the fact that Constructor Injection easily leads to Constructor over-injection, since this is an indication that our class does too much and it is a signal that we should redesign such class.

而不是实现跨领域关注点,例如基类中的日志记录,缓存和授权,请使用composition实现它们。例如,您可以使用中间件装饰器拦截器可以将横切关注点应用于请求(或此类请求的特定服务)。

Instead of implementing cross-cutting concerns such as logging, caching, and authorization in a base class, implement them using composition. For instance, you can use middleware, decorators or interceptors to apply cross-cutting concerns to a request (or a specific service of such request).

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

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