我有一个抽象的基本控制器,它有一个构造函数,我希望在构建控制器时由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框架的依赖性吗?是构造函数注入唯一方式来填充heirachy中的依赖。
由于
答案 0 :(得分:54)
显式调用基类构造函数是在C#中使用构造函数注入执行此操作的唯一方法。您似乎应该从BaseController
和PublicController
中删除无参数构造函数,因为当记录器可用时,它们永远不会被实际调用。
将依赖项注入基本控制器的问题是使用ASP.NET MVC和IoC的常见问题。有几种选择/思想流派。
1。)使用聚合服务。为了简化派生类构造函数,创建一个服务,公开或委托基本控制器所需的所有不同服务(例如IBaseControllerDependencies
或类似的。)然后将这一项服务传递给BaseController
,就像你在这里做ILogger
。
根据您的应用程序和您正在使用的基类数量,有各种优缺点。 Google可以通过“Autofac聚合服务”了解更多信息。
2。)使用属性注入。将基类的ILogger
属性设置为public,并使用以下命令配置容器:
builder.RegisterControllers().PropertiesAutowired();
属性注入并不是Autofac中的首选技术。构造函数的角色 接受依赖关系,而可写属性通常被视为代码异味,因此Autofac并不真正针对这种情况进行优化。其中一个缺点是不应该经常注入
的可写属性是错误的,结果很奇怪。 3.)将基本控制器功能重构为各种动作过滤器。 Autofac可以将动作过滤器注入MVC动作调用管道。因此,过滤器可以采用基类上的依赖关系,并且可以以交叉方式应用相同的关注点。有关此内容的更多信息,ExtensibleActionInvoker
和.InjectActionInvoker()
指向您需要的信息。并非总能解决所有问题。
4,也是对第二个问题的回答。)使用DependencyResolver.Current
中的服务位置解决基本控制器依赖关系。
var logger = DependencyResolver.Current.GetService<ILogger>();
不鼓励这样做的原因是它使得生成的应用程序更难理解,因为通过查看一个位置(构造函数)不再可能看到组件所依赖的服务。确定必须配置的内容在可以使用特定组件之前的容器中,必须查看组件的整个代码库以查找GetService()
调用。单元测试时存在明显的障碍。
希望这有帮助,我知道的大脑转储:)其他人可能会为这些添加更多的想法。
答案 1 :(得分:2)
我没有评论权限要求更多详细信息,但我需要查看您的注册码,以了解您的期望以及容器未达到预期的原因。
关于你的其他问题:类不一定有办法自己解决,但是一个类可以依赖于一个已知类型的自动可解析对象工厂(这通常就足够了)。如果您已注册A
,则可以依赖Func<A>
。在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/)。祝你好运!
答案 2 :(得分:1)
Autofac for .NET Core
安装的
PM> Install-Package Autofac.Core.NonPublicProperty
使用
builder.RegisterType<AppService>()
.AsImplementedInterfaces()
.AutoWireNonPublicProperties();