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

Я использую GlassMapper в своем проекте SC7. Он настраивает контейнер Castle Windsor IoC «из коробки», позволяя добавлять пользовательскую конфигурацию. Я добавил некоторые зависимости в свой конструктор контроллера и заменил 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);
    }
}

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


person Hellraiser    schedule 18.03.2015    source источник
comment
Хорошо, я был прав: если вы используете полное имя для указания своего контроллера и действия, Sitecore использует отражение для загрузки контроллера, ожидая, что у него будет конструктор без параметров. И это делается в классе Sitecore.Mvc.Controllers.ControllerRunner.   -  person Hellraiser    schedule 18.03.2015


Ответы (1)


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

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

person Hellraiser    schedule 19.03.2015