【问题标题】:Autofac, dynamic dependency Injection for MVC controllersAutofac,MVC控制器的动态依赖注入
【发布时间】:2015-02-11 16:18:20
【问题描述】:

我有一个带有 UnitOfWork 接口和管理器的项目设置。当我只需要使用 accountMananger 作为控制器的基础时,所有这些都运行良好。

    protected BaseController(IAccountManager acctManager)
    {
        _accountManager = acctManager;
    }

我的控制器就是这样创建的,并且可以正常工作。

  public class AccountController : BaseController
  {
    public AccountController(IAccountManager accountManager)
        : base(accountManager)
    {
    }

现在我正在创建其他业务经理,并且我意识到在项目结束时我的 BaseController 构造函数将会很大,或者我将根据我所在的控制器加载各种签名。如果我忘记了某些东西并需要另一个管理器并更改了一个构造函数,那么所有其他控制器也需要更改。

我的意思是,我实际上总是希望在基础中注入/解析 accountManager。我可以这样做吗?因为我 99% 都在检查授权。

我已经阅读了有关 ControllerFactories 的信息,但也有人提到要实现 IDependancyResolver ,但没有示例,这是他的首选方式。

我可以看到这成为基于我需要的控制器创建构造函数的巨大负担,而我还没有。

任何人都可以给我一个示例,说明如何在我需要的时候轻松访问我在基地的经理。我的意思是,无论如何,它们都已创建并准备好解决.. 那我为什么需要以如此奇怪的方式传递它们呢?

对不起。刚刚学习了 DI,这是一个很好的教程,但是你可以看到缺少一些进一步的解释。

【问题讨论】:

    标签: c# asp.net-mvc dependency-injection autofac


    【解决方案1】:

    您与客户经理的联系方式称为Cross-Cutting Concern。有几种不同的方法可以给这只猫换皮,但你应该避免将相同的依赖注入到每个控制器中。

    一般来说,最好避免继承,因为这会导致类之间的紧密耦合。紧密耦合在这里很明显 - 如果您以后需要一个没有 IAccountManager 作为依赖项的控制器怎么办?

    在这种特殊情况下,您可以使用 MVC 中的内置松散耦合授权框架 - AuthorizeAttribute,这是处理对控制器操作方法的访问的常规方式。

    [Authorize] 
    public class AccountController : Controller
    {
        public AccountController () { . . . }
    
        [AllowAnonymous]
        public ActionResult Register() { . . . }
    
        public ActionResult Manage() { . . . }
    
        public ActionResult LogOff() { . . . }
    } 
    

    还有其他几个实现横切关注点的选项 - 实现 IActionFilter - see this for a DI friendly exampleinterception(一些 DI 容器支持),使用 Decorator Pattern,并将依赖项置于环境上下文中(例如 HttpContext.Items)。

    我可以看到这成为基于我需要的控制器创建构造函数的巨大负担,而我还没有。

    这就是为什么您应该继承DefaultControllerFactory 并在应用程序启动时为它提供一个DI 容器实例(在composition root 中)。向控制器提供依赖项通常是容器的责任,尤其是在您的应用程序很大的情况下。

    public class AutofacControllerFactory
        : DefaultControllerFactory
    {
        private readonly IContainer container;
    
        public InjectableControllerFactory(IContainer container)
        {
            if (container == null)
                throw new ArgumentNullException("container");
            this.container = container;
        }
    
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (requestContext.HttpContext.Request.Url.ToString().EndsWith("favicon.ico"))
                return null;
    
            return controllerType == null ?
                base.GetControllerInstance(requestContext, controllerType) :
                this.container.Resolve(controllerType) as IController;
        }
    }
    

    我强烈建议您阅读本书Dependency Injection in .NET。 DI 是软件开发中最容易被误解的概念之一,值得投资自己详细研究该主题,而不必筛选 Internet 上的错误信息。正确使用 DI 可以获得很多好处,但使用不当往往比完全不使用 DI 更糟糕。

    【讨论】:

    • 感谢您提供一些不错的信息。我们已经使用了 Authorize 属性,但是基本控制器覆盖了 OnAuthroizing 进行一些检查,设置会话,要求 accountManager 在每次调用时调用 accountRepo 以更新各种内容。但是正如您建议的 controllerFacotry,这似乎被建议了 9/10 次,我很可能需要弄清楚如何做到这一点。我正在努力寻找使用 DI 的真正好处,但我真的很想了解它的真正含义。谢谢+1
    • LOL- 我想我是AN ABSTRACT FACTORY ON STEROID 的经典例子 :) 没学过...
    • 好吧,可以继承 Authorize 属性来做到这一点,尽管出于 DI 的目的,最好将其分离为 IAuthorizationFilter 和一个没有类似于here 所示行为的属性.将每个关注点分成一个单独的服务也是一种最佳实践——(更新各种东西,做一些检查)。事实上,它被命名为 AccountManager 是一种代码味道,表明它正在做不止一件事(这很糟糕)。
    • 是的,现在我开始认为这个项目根本不需要 DI。它定义明确,几乎可以肯定 web 层不会改变。我们已经可以换出存储库或 DB 的实现了。那么为什么还要在 MVC 应用程序中使用 DI 的麻烦。获得了 UnitOfWork 和业务松散耦合,并且测试替身可以在以后与 DI 一起使用。可能只是我们在这里使用 DI,因为……每个人都在谈论它。如果我正确理解了第一章,那么这里就不需要 DI。
    • 嗯,不使用 DI 和不使用 DI 容器是有区别的。您可以在没有容器的情况下很好地使用 DI 模式。但这并不意味着您不应该遵循使用构造函数注入的做法。可测试性只是 DI 的好处之一。主要好处之一是无需更改即可轻松扩展软件(不仅仅是交换实现,这也是一个好处)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 2014-09-12
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多