【问题标题】:Umbraco MVC with Castle WindsorUmbraco MVC 与温莎城堡
【发布时间】:2014-02-17 17:29:21
【问题描述】:

有没有人有任何示例代码可以让 Umbraco MVC 与 Castle Windsor 依赖注入框架一起工作?我遇到的问题是让我的表面控制器使用可注入的参数化构造函数。我知道我做错了什么,但不确定是什么。

我在这里遵循了(非 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)
    {
        ....
    }
}

如果有人有一些有效的示例代码,我将不胜感激。我之前已经将 Ninject 与 Umbraco 连接起来没有任何问题,但在这个项目中,我与 Castle Windsor 相关联,而且进展不快!提前致谢。

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

【问题讨论】:

    标签: c# asp.net-mvc castle-windsor umbraco


    【解决方案1】:

    我相信你的问题就在这里:

    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<IController>().LifestyleTransient());
    
            FilteredControllerFactoriesResolver.Current.InsertType<FilteredControllerFactory>(0);
        }
    }
    

    这种方法应该适用于路线劫持和表面控制器。

    最后,请注意,如果您还想支持注入 API 控制器,则需要单独连接。例如:

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

    CompositionRoot 是您自己的 Windsor 组合根类。

    Gist here 也可能有用。

    【讨论】:

    • 非常感谢您抽出宝贵的时间。我几天都没有时间测试它,但这一切都很有意义。一旦我尝试过,我一定会报告回来。
    • 您的要点中的对象工厂事情有点复杂,但它确实有效。干杯!
    【解决方案2】:

    我读过 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 也将被映射并正确解析。

    最近我在 Umbraco 应用中写了几篇关于 DI 的文章:

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多