Sitecore 7 IoC и визуализация контроллеров

Я использую GlassMapper в моем проекте SC7. Он настраивает IoC-контейнер Castle Windsor "из коробки", позволяя добавить пользовательскую конфигурацию. Я добавил некоторые зависимости в конструктор моего контроллера и переписал SitecoreControllerFactory по умолчанию на другой, использующий контейнер Castle для их разрешения. Я добавил контроллер как контроллер рендеринга, но он не работает.

Окунувшись в нее, я понял, что фабрика контроллеров по умолчанию вообще не вызывается, хотя она настроена правильно. Вместо этого 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);
    }
}

Вы не можете видеть зависимость в конструкторе, так как теперь я разрешаю его, вызывая контейнер напрямую.

1 ответ

Решение

Что ж, решение заняло некоторое время, но в итоге я его получил: я переписал 5 классов: GetControllerRenderer, ControllerRenderer, ControllerRunner, ControllerFactory и SitecoreControllerFactory.

В GetControllerRenderer метод GetRenderer вызывает ControllerRenderer, в котором метод Render вызывает ControllerRunner. В ControllerRunner я переопределил метод CreateController для обхода кода Sitecore, который загружает контроллер отражением и использует новую фабрику контроллеров на основе Castle Windsor.

Другие вопросы по тегам