使用Autofac与Mvc控制器构造函数注入
本文关键字:构造函数 注入 控制器 Mvc Autofac 使用 | 更新日期: 2023-09-27 18:13:48
我在autofacc构造函数注入方面遇到了麻烦。我的问题在某种程度上已经解决了,但我正在向社区寻求一个完整的解决方案。
这适用于DI
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.InstancePerHttpRequest();
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.AsImplementedInterfaces()
.InstancePerHttpRequest();
这是我的控制器
public class HomeController : BaseController
{
public HomeController(IPlugin plugin)
{
}
}
我有一个模块来解决IPlugin注入。我想知道为什么我需要把.AsImplementedInterfaces()
取出来做这个工作。我更喜欢使用接口,因为我在运行时使用MEF从其他程序集导入控制器。
感谢japonex(见下面的评论)我已经更新了我的解决方案。下面是我为使一切正常工作所做的。
首先,我的项目有自己的控制器,然后我使用MEF从其他程序集导入控制器。
我当前项目的控制器必须在没有.AsImplementedInterfaces()
调用的情况下注册,所以像这样
builder.RegisterControllers(typeof(MvcApplication).Assembly).InstancePerRequest();
这将使控制器进入Autofac使用类型而不是作为接口(MyProject.Controllers.HomeController
代替System.Web.Mvc.IController
)。
接下来,在我的插件项目中,我只需要导出类型而不是作为接口。所以我用
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : PluginController
而不是
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : PluginController
注意Export
属性的区别。
接下来我将当前DependencyResolver
设置为AutofacDependencyResolver
。
最后,但并非最不重要的是,我创建了一个自定义ControllerFactory来创建控制器。从技术上讲,这是不需要的,因为我不再使用接口,但是我有代码在创建控制器之前检查它的状态。这使我可以很容易地从管理区域启用/禁用插件。
所以问题的根源在于autoface需要类型而不是接口来正确解决。我确信这可以通过接口来完成,但这个解决方案对我来说很有效。我想要使用接口的唯一真正原因是,这样我就可以在不知道类型的情况下从autoface请求所有控制器。
public class MyControllerFactory : DefaultControllerFactory
{
private readonly IContainer _container;
public PortalControllerFactory(IContainer container)
{
_container = container;
}
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
Type controllerType = GetControllerType(requestContext, controllerName);
if(controllerType == null)
{
throw new HttpException(404, ErrorMessages.Http404);
}
IPlugin plugin = PluginManager.Current.GetPlugin(controllerType);
if (plugin != null && plugin.Status != Common.Enums.PluginStatus.Enabled)
{
//the controller/plugin is disabled so modify the route data and return the controller
RouteData data = new RouteData();
data.Values.Add("controller", "plugin");
data.Values.Add("action", "disabled");
data.Values.Add("plugin", plugin.Name);
requestContext.RouteData = data;
return ViewRenderer.CreateController<Project.Controllers.PluginController>(data);
}
var controller = ((AutofacDependencyResolver)DependencyResolver.Current).RequestLifetimeScope.Resolve(controllerType);
return controller as IController;
}
}
当您使用.AsImplementedInterfaces
时,您说对于每个具体类型,autofacc为每个接口实现注册此类型。
你将Assembly中的所有控制器注册到IController可能因为你没有任何规则(键控或命名注册)来决定返回哪个具体类型,autofacc可能会返回IController的最后一个注册。
尝试调用容器。下定决心,看看你能得到什么。
考虑如果你有:
public class HomeController : BaseController
{
public HomeController(IPlugin plugin)
{
}
}
和
public class Home2Controller : BaseController
{
public Home2Controller(IPlugin plugin)
{
}
}
HomeController将被注册到IController和Home2Controller也将被注册到IController。
我认为Autofac的默认行为是使用最后一个注册如果你不使用任何类型的规则(键控或命名注册)