Umbraco MVC与温莎城堡
有没有人有任何示例代码让Umbraco MVC使用Castle Windsordependency injection框架? 我遇到的问题是让我的表面控制器使用可注射的参数化构造函数。 我知道我做错了什么但不确定是什么。
我在这里遵循了(非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() .LifestyleTransient());
我得到的例外是’找不到支持服务的组件Umbraco.Web.Mvc.RenderMvcController’,当我用一个参数化构造函数调用一个表面控制器时,由下面的GetControllerInstance
方法抛出:
public class TestSurfaceController : SurfaceController { public TestSurfaceController(INameService nameService) { .... } }
如果有人有一些有效的示例代码,我真的很感激。 我之前已经把Ninject和Umbraco连接起来没有遇到任何麻烦,但是在这个项目中,我被绑在温莎城堡上并且无处可去! 提前致谢。
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); } }
我相信你的问题在这里:
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
这将替换所有控制器的控制器工厂,包括RenderMVCController,而Castle无法找到该类型的匹配组件。
诀窍是使用FilteredControllerFactoryResolver,它允许Umbraco根据您提供的某些条件决定使用哪个控制器(在这种情况下,您的容器是否可以解析控制器类型)。 组合不像直接MVC应用程序(恕我直言)那样干净,但它的工作原理。
这是一个实现IFilteredControllerFactory接口的过滤控制器的(Umbraco 7.x)示例:
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); } }
和相应的代码来设置组合(使用ApplicationEventHandler ):
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().LifestyleTransient()); FilteredControllerFactoriesResolver.Current.InsertType(0); } }
这种方法既适用于路线劫持,也适用于地面控制器。
最后,请注意,如果您还想支持注入API控制器,则需要单独进行连接。 例如:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new CompositionRoot(Container.Kernel))
其中CompositionRoot是您自己的Windsor组合根类。
这里的要点也可能有用。
我已经阅读了Kristopher的答案,我发现它很有趣,因为我不知道IFilteredControllerFactory及其用途。 感谢分享。
无论如何,通常在我的项目中我有很多dll包含每个自己的控制器,所以我更喜欢以更一般的方式注册所有控制器:
container.Register( Classes .FromAssemblyInDirectory(new AssemblyFilter(AssemblyDirectory)) .BasedOn() .LifestyleTransient());
哪里
/// /// Local Directory where are present all the assemblies /// 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也将被映射并正确解析。
最近我在Umbraco应用程序中写了几篇关于DI的文章:
- MVC控制器工厂
- MVCfilter中的属性注入
希望它可以提供帮助