使用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;
    }
}

使用Autofac与Mvc控制器构造函数注入

当您使用.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的默认行为是使用最后一个注册如果你不使用任何类型的规则(键控或命名注册)