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.