2014-07-18 109 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

相關問題