Sitecore 7 IoC 和控制器渲染

Sitecore 7 IoC and Controller Renderings

我在我的 SC7 项目中使用 GlassMapper。它配置 Castle Windsor IoC 容器 "out of the box",允许添加自定义配置。我向我的控制器构造函数添加了一些依赖项,并使用 Castle 的容器来解决它们,从而覆盖了默认的 SitecoreControllerFactory。 我将控制器添加为Controller Rendering,但它似乎不起作用。

深入研究,我意识到默认控制器工厂根本没有被调用,尽管它配置正确。相反,Sitecore 似乎寻求替代管道,调用 Sitecore.Mvc.Controllers.ControllerRunner,它使用反射加载控制器并创建它的实例,由于构造函数需要依赖项,它会抛出异常。

这是代码。

初始化:

public class Initialize
{
    public void Process(PipelineArgs args)
    {
        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new WebFormViewEngine());
        ViewEngines.Engines.Add(new ThemedRazorEngine());

        GlassMapperSc.Start();

        SetupControllerFactory(args);
    }

    public virtual void SetupControllerFactory(PipelineArgs args)
    {
        var container = Utils.Ioc.Ioc.CurrentContainer;
        if (container == null)
        {
            return;
        }

        var controllerFactory = new WindsorControllerFactory(container);

        var sitecoreControllerFactory = new SitecoreWindsorControllerFactory(controllerFactory);
        ControllerBuilder.Current.SetControllerFactory(sitecoreControllerFactory);
    }
}

Sitecore 控制器工厂:

public class SitecoreWindsorControllerFactory : SitecoreControllerFactory
{
    public SitecoreWindsorControllerFactory(IControllerFactory innerFactory) : base(innerFactory)
    {
    }

    protected override IController CreateControllerInstance(RequestContext requestContext, string controllerName)
    {
        return controllerName.EqualsText(SitecoreControllerName) ? CreateSitecoreController(requestContext, controllerName) : InnerFactory.CreateController(requestContext, controllerName);
    }
}

默认控制器工厂:

public class WindsorControllerFactory : DefaultControllerFactory
{
    private const int PageNotFoundStatus = 404;

    private readonly IWindsorContainer _container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        _container = container;
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        // todo: wrap this in the final implementation
        if (!TypeHelper.LooksLikeTypeName(controllerName))
        {
            return base.CreateController(requestContext, controllerName);
        }
        var type = TypeHelper.GetType(controllerName);

        return type != null ? GetControllerInstance(requestContext, type) : null;
    }

    public override void ReleaseController(IController controller)
    {
        _container.Release(controller);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            // todo: the request context should be wrapped in final implementation.
            throw new HttpException(
                PageNotFoundStatus,
                string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
        }

        return _container.Resolve(controllerType) as IController;
    }
}

控制器:

ublic class LanguagePickerController : Controller
{
    private readonly ISitecoreContext _context;

    public LanguagePickerController()
    {
        _context = Ioc.CurrentContainer.Resolve<ISitecoreContext>();
    }

    public ActionResult LanguagePickerIndex()
    {
        //var context = new SitecoreContext();
        var dataSource = RenderingContext.Current.Rendering.DataSource;
        var model = _context.GetItem<LanguagePicker>(dataSource);

        // ReSharper disable once Mvc.ViewNotResolved
        return View("LanguagePicker",model);
    }
}

你看不到构造函数中的依赖关系,因为现在我正在解决它直接调用容器。

好吧,这个解决方案花了一段时间,但我终于明白了: 我覆盖了 5 类:GetControllerRenderer、ControllerRenderer、ControllerRunner、ControllerFactory 和 SitecoreControllerFactory。

在GetControllerRenderer中,GetRenderer方法调用ControllerRenderer,Render方法中调用ControllerRunner。在 ControllerRunner 中,我覆盖了方法 CreateController 以绕过 Sitecore 代码,该代码通过反射加载控制器并使用基于 Castle Windsor 的新控制器工厂。