【问题标题】:ASP.NET Core DI Constructor vs RequestServices [duplicate]ASP.NET Core DI 构造函数与 RequestServices [重复]
【发布时间】:2018-05-30 08:08:42
【问题描述】:

为什么通过HttpContext.RequestServicesIServiceProvider 请求服务被认为是不好的做法。我到处都能读到这句话:

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


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

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

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

所有服务都继承自base,其中包含管理权限、缓存sql请求的逻辑......
使用构造函数方法,我得到了非常复杂的调用 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 我简化了基于构造函数的调用:

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)。

如果我反对构造方法。如果生命周期为 Scoped,则为 MyServices 调用 ServiceProvider.GetRequiredService 是否会影响性能。

【问题讨论】:

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


    【解决方案1】:

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

    这被认为是一种不好的做法,因为它是 Service Locator anti-pattern 的实现。

    您试图通过将许多常见的依赖项和常见的逻辑移动到基类中来保持控制器类的小型化,但这本身就是一种反模式,因为:

    • 尽管从基类中解析了依赖关系,但这些依赖关系仍然是隐藏的,正如this article 解释的那样。这意味着依赖项对您的单元测试和 DI 容器是隐藏的,后者将无法对您的对象图进行分析。
    • 将依赖项移至基类并不会降低类的复杂性,因为基类始终与派生类紧密耦合
    • 会导致很多职责被塞进基类,会导致基类违反Single Responsibility Principle。这可以迫使基类成为神类并不断变化。

    基类使用继承,而软件开发中的普遍共识是您应该支持Composition over inheritance

    由于您应该支持组合,这会自动导致依赖注入。在没有基类的情况下,发现单一责任原则违规会立即变得更容易,因为您的构造函数将获得更多参数。再次注意,使用服务定位器时依赖项的数量不会改变,只是更难计算。

    您应该接受构造函数注入很容易导致Constructor over-injection 的事实,因为这表明我们的类做了太多事情,这表明我们应该重新设计此类。

    不要在基类中实现cross-cutting concerns(例如日志记录、缓存和授权),而是使用组合来实现它们。例如,您可以使用middlewaredecoratorsinterceptors 将横切关注点应用于请求(或此类请求的特定服务)。

    【讨论】:

    • 不知道我怎么会错过重复的问题,但我很高兴我做到了。这是迄今为止最好的答案。
    猜你喜欢
    • 2021-04-05
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    • 2022-06-29
    • 2019-05-21
    相关资源
    最近更新 更多