使用 autofac 将构造函数注入到基类中

Posted

技术标签:

【中文标题】使用 autofac 将构造函数注入到基类中【英文标题】:Constructor injection into a base class using autofac 【发布时间】:2011-11-04 04:10:03 【问题描述】:

我有一个抽象的基础控制器,它有一个构造函数,我希望在构建控制器时由 autofac 填充。

public abstract class BaseController : Controller

    protected ILogger  get; private set; 

    protected BaseController()
    
    

    protected BaseController(ILogger logger)
    
        Logger = logger;
    

当我从中派生控制器时,这似乎不起作用。

只有当我从控制器显式调用构造函数时,我才能让它工作。这是正确的做法吗?

public class PublicController : BaseController

    public PublicController()
    
    

    public PublicController(ILogger logger) : base(logger)
    

    

此外,使用 MVC 集成程序集,似乎没有办法共享容器以供其他类进行自己的解析。我在某处读到不鼓励这样做,为什么不呢?这只是为了解耦任何单个 ioc 框架的依赖关系吗?构造函数注入是唯一在层次结构中填充依赖项的方式吗?

【问题讨论】:

【参考方案1】:

显式调用基类构造函数是在 C# 中使用构造函数注入执行此操作的唯一方法。看起来您应该从 BaseControllerPublicController 中删除无参数构造函数,因为当记录器可用时,它们实际上不应该被调用。

将依赖项注入基本控制器的问题是使用 ASP.NET MVC 和 IoC 的常见问题。有几种选择/思想流派。

1.) 使用聚合服务。为了使派生类构造函数保持简单,请创建一个服务,该服务公开或委托给基本控制器所需的所有不同服务(例如IBaseControllerDependencies 或类似的。)然后将这个服务传递给BaseController,就像你正在做的那样ILogger这里。

根据您的应用程序和您使用的基类数量,有各种优缺点。 Google 的“Autofac 聚合服务”可以查看更多信息。

2.) 使用属性注入。将基类上的 ILogger 属性设为公开,并使用以下命令配置容器:

builder.RegisterControllers().PropertiesAutowired();

属性注入并不是 Autofac 中真正的首选技术。构造函数的角色接受依赖,而可写属性通常被视为代码异味,因此 Autofac 并没有真正针对这种情况进行优化。缺点之一是不应该注入的可写属性经常被错误地注入,从而产生奇怪的后果。

3.) 将基本控制器功能重构为各种动作过滤器。 Autofac 可以将动作过滤器注入到 MVC 动作调用管道中。因此,过滤器可以获取基类上的依赖关系,并且可以以横切方式应用相同的关注点。有关此内容的更多信息,请访问网络,ExtensibleActionInvoker.InjectActionInvoker() 指向您需要的信息。并非总能解决所有问题。

4,也是第二个问题的答案。)使用来自DependencyResolver.Current 的服务位置解决基本控制器依赖关系。

var logger = DependencyResolver.Current.GetService<ILogger>();

不鼓励这样做的原因是它使生成的应用程序更难理解,因为不再可能通过查看一个地方(构造函数)来查看组件所依赖的服务。确定必须配置的内容在容器中使用特定组件之前,必须查看组件的整个代码库以找到 GetService() 调用。单元测试时的明显障碍。

希望这会有所帮助,我知道有点脑残 :) 其他人可能会为这些添加更多想法。

【讨论】:

【参考方案2】:

我没有评论权限来询问更多细节,但我需要查看您的注册码以了解您的期望以及容器不符合这些期望的原因。

关于您的其他问题:类不一定有办法自己解析,但类可以依赖于已知类型的自动可解析对象工厂(这通常就足够了)。如果你注册了A,你可以依赖Func&lt;A&gt;。 Autofac中有很多这样的关系类型;见http://code.google.com/p/autofac/wiki/RelationshipTypes。

不鼓励“共享容器”,因为它往往会隐藏类的依赖关系。如果对容器有依赖,或者作为全局“IoC”对象引用,那么特定依赖的表现力就会丢失。

解决层次结构中的依赖关系应该不是问题,因为您已经在使用 c'tor 注入我不确定您的问题是什么。还有一些辅助问题,例如如果您的基类依赖项发生更改,则修改所有子类。幸运的是,Autofac 在 Aggregate Services (http://code.google.com/p/autofac/wiki/AggregateService) 中有一个解决方案。

Autofac 是一个很棒的深度工具。还有一个建议,如果您刚刚开始,请花一些时间了解对象生命周期和生命周期范围(尤其是 http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/)。祝你好运!

【讨论】:

【参考方案3】:

适用于 .NET Core 的 Autofac

安装

PM> Install-Package Autofac.Core.NonPublicProperty

使用

builder.RegisterType<AppService>()
  .AsImplementedInterfaces()
  .AutoWireNonPublicProperties();

【讨论】:

请注意,如果属性是由 AutoFac 定义的,这可能会导致错误设置。

以上是关于使用 autofac 将构造函数注入到基类中的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Xamarin 和 Autofac 将构造函数依赖项注入 ViewModel?

Autofac的基本使用

如何在构造函数中注入 IEnumerable<ICustomRepository>,以便我可以决定在基类中使用哪一个?

是否可以使用 Autofac 将已解析对象的列表注入构造函数?

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)

[Asp.Net Core]Autofac单抽象多实现构造函数注入