2014-02-17 151 views
5

有沒有人有任何示例代碼獲取Umbraco MVC與Castle Windsor依賴注入框架一起工作?我遇到的問題是讓我的表面控制器使用可注射的參數化構造函數。我知道我做錯了什麼,但不知道是什麼。Umbraco MVC與城堡溫莎

我也跟着(非一把umbraco)這裏的教程 - http://docs.castleproject.org/Windsor.Windsor-tutorial-part-four-putting-it-all-together.ashx - 這對App_Start基本上意味着我運行這段代碼:

var container = new WindsorContainer().Install(FromAssembly.This()); 
var controllerFactory = new MyCustomControllerFactory(container.Kernel); 
ControllerBuilder.Current.SetControllerFactory(controllerFactory); 

代碼MyCustomControllerFactory如下。

另外,我實現IWindsorInstaller包含以下內容:

container.Register(Classes.FromThisAssembly() 
    .BasedOn<SurfaceController>() 
    .LifestyleTransient()); 

我得到的例外是「支持Umbraco.Web.Mvc.RenderMvcController發現服務的成分,不」,由GetControllerInstance拋出

public class TestSurfaceController : SurfaceController 
{ 
    public TestSurfaceController(INameService nameService) 
    { 
     .... 
    } 
} 

如果任何人有一些示例代碼工作我會很感激:方法時,我稱之爲地面控制器與parametised構造如下。我之前用Umbraco連接了Ninject,但沒有遇到任何問題,但是在這個項目中,我被綁定到溫莎城堡並且無處不在!提前致謝。

MyCustomControllerFactory.cs:

public class MyCustomControllerFactory : DefaultControllerFactory 
{ 
    private readonly IKernel kernel; 

    public FastStartControllerFactory(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public override void ReleaseController(IController controller) 
    { 
     kernel.ReleaseComponent(controller); 
    } 

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
    { 
     if (controllerType == null) 
     { 
      throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path)); 
     } 
     return (IController)kernel.Resolve(controllerType); 
    } 
} 

回答

7

我相信你的問題是在這裏:

ControllerBuilder.Current.SetControllerFactory(controllerFactory); 

這是更換控制器工廠所有控制器,包括RenderMVCController,和城堡找不到匹配該類型的組件。

訣竅是使用FilteredControllerFactoryResolver,它允許Umbraco根據您提供的一些標準(在這種情況下,您的容器是否可以解析控制器類型)決定使用哪個控制器。構圖並不像直MVC應用程序(恕我直言)那樣乾淨,但它的工作原理。

下面是一個(一把umbraco 7.x中)經濾波的控制器,實現了IFilteredControllerFactory界面的示例:(使用ApplicationEventHandler

public class FilteredControllerFactory : ControllerFactory, IFilteredControllerFactory 
{ 
    public bool CanHandle(RequestContext request) 
    { 
     Type controllerType = GetControllerType(request, request.RouteData.Values["controller"].ToString()); 
     return ApplicationStartup.Container.Kernel.HasComponent(controllerType); 
    } 
} 

以及相應的代碼來設置組合物:

public class ApplicationStartup : ApplicationEventHandler 
{ 
    internal static IWindsorContainer Container; 

    protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) 
    { 
     base.ApplicationStarting(umbracoApplication, applicationContext); 

     Container = new WindsorContainer() 
      .Install(Configuration.FromAppConfig()) 
      .Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient()); 

     FilteredControllerFactoriesResolver.Current.InsertType<FilteredControllerFactory>(0); 
    } 
} 

這種方法應該適用於路由劫持和地面控制器。

最後,請注意,如果您還想支持注入API控制器,則需要單獨連線。例如:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new CompositionRoot(Container.Kernel)) 

其中CompositionRoot是您自己的Windsor組合根類。

The Gist here也可能證明有用。

+0

上謝謝你這麼多的寶貴時間這個。我幾乎沒有時間來測試它,但這一切都非常有意義。一旦我嘗試過,我一定會報告回來。 – getsetcode

+0

你的要點中的對象工廠事情複雜一點,但它的工作。乾杯! –

0

我讀過Kristopher的回答,我發現它很有趣,因爲我不知道IFilteredControllerFactory及其用法。感謝分享。

無論如何,通常在我的項目我有很多包含每個自己的控制器的dll,所以我更喜歡一個更一般的方式來註冊的所有控制器:

container.Register(
      Classes 
      .FromAssemblyInDirectory(new AssemblyFilter(AssemblyDirectory)) 
      .BasedOn<IController>() 
      .LifestyleTransient()); 

其中

/// <summary> 
    /// Local Directory where are present all the assemblies 
    /// </summary> 
    static public string AssemblyDirectory 
    { 
     //Snippet code from: https://gist.github.com/iamkoch/2344638 
     get 
     { 
      var codeBase = Assembly.GetExecutingAssembly().CodeBase; 
      var uri = new UriBuilder(codeBase); 
      var path = Uri.UnescapeDataString(uri.Path); 
      return Path.GetDirectoryName(path); 
     } 
    } 

通過這種方式,Umbraco的RenderMVCController也將被映射並正確解析。

最近我寫了幾個關於DI的文章在一把umbraco應用:

希望它可以幫助