2014-07-18 75 views
3

我在使用Autofac构造函数注入时遇到问题。我有点解决了我的问题,但我正在向社区寻求一个完整的解决方案。使用Autofac与Mvc控制器构造函数注入

这适用于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在运行时从其他程序集导入IControllers。

更新

感谢japonex(见下文评论)我已经更新了我的解决方案。以下是我所做的一切工作。

首先,我的项目有自己的控制器,然后使用MEF从其他组件导入控制器。

控制器,用于我当前的项目必须进行登记,而不.AsImplementedInterfaces()调用,因此像这样

builder.RegisterControllers(typeof(MvcApplication).Assembly).InstancePerRequest(); 

这将使控制器进入Autofac使用类型,而不是作为一个接口(而不是MyProject.Controllers.HomeControllerSystem.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来创建控制器。从技术上讲,这是不需要的,因为我不再使用接口,但是我有代码在创建它之前检查控制器的状态。这使我可以轻松地从管理区域启用/禁用插件。

所以问题的根源在于Autofac需要类型而不是接口才能正确解析。我确信这可以通过接口来完成,但这种解决方案对我来说很合适。我想要使​​用接口的唯一真正原因是因为我可以在不知道类型的情况下向Autofac请求所有控制器。

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

回答

0

当您使用.AsImplementedInterfaces你是说,对于每个具体类型,Autofac注册这种类型的每个接口的实现。

所以,你正在将你的Assembly中的所有控制器注册到IController,并且因为你没有任何规则(键控或命名注册)来决定哪个具体类型返回,Autofac可能会返回IController的最后注册。

尝试调用container.Resolve,看看你得到了什么。

想想看,如果您有:

public class HomeController : BaseController 
{ 
    public HomeController(IPlugin plugin) 
    { 

    } 
} 

public class Home2Controller : BaseController 
{ 
    public Home2Controller(IPlugin plugin) 
    { 

    } 
} 

的HomeController将被注册到一个IController和 Home2Controller也将被注册到一个IController。

而且我觉得Autofac的默认行为是使用最后一次注册的,如果你不使用任何规则(键入或命名注册)

+0

所以,当我使用'AsImplementedInterfaces',代码没有按”因为DefaultControllerFactory抱怨控制器上没有空的构造函数。堆栈跟踪甚至没有与Autofac相关的任何内容。这一切都源自DefaultControllerFactory。这让我觉得使用IController与AutofacDependencyResolver不搭配。 – Matt

+0

我认为你需要定制你的ControllerFactory。如果您创建自定义ControllerFactory并注册到IControllerFactory,则可以使其工作,因为您已将DependencyResolver设置为Autofac。 看看[这](http://stackoverflow.com/questions/13555465/custom-controllerfactory-with-autofac)可以帮助你。 – japoneizo

+0

我觉得我需要这样做。我认为虽然AutofacDependencyResolver应该已经照顾到了这一点,但我想不是。谢谢。 – Matt

相关问题