具有统一性的Sitecore DI

具有统一性的Sitecore DI,sitecore,inversion-of-control,sitecore7.2,glass-mapper,sitecore-mvc,Sitecore,Inversion Of Control,Sitecore7.2,Glass Mapper,Sitecore Mvc,我正在尝试建立一个全新的Sitecore 7.2网站,我希望将MVC 5、Glass Mapper和Microsoft Unity集成为DI容器,Sitecore不想玩得很好 我的设想是: 获得了一个名为PoC.Quotes.Web的Web项目-它将只包含CSS、HTML和任何其他资产,而不包含控制器 获得一个名为PoC.Quotes.Controllers的类库项目-这只包含控制器 获得了一个名为PoC.Quotes.DataLayer的类库项目-它包含一个接口ISitecoreReposit

我正在尝试建立一个全新的Sitecore 7.2网站,我希望将MVC 5、Glass Mapper和Microsoft Unity集成为DI容器,Sitecore不想玩得很好

我的设想是:

获得了一个名为PoC.Quotes.Web的Web项目-它将只包含CSS、HTML和任何其他资产,而不包含控制器 获得一个名为PoC.Quotes.Controllers的类库项目-这只包含控制器 获得了一个名为PoC.Quotes.DataLayer的类库项目-它包含一个接口ISitecoreRepository及其具体实现SitecoreRepository SitecoreRepository类有一个构造函数,它接收1个参数,Glass Mapper上下文,我的一个控制器在构造函数中接收1个参数…ISitecoreRepository

Sitecore存储库类:

public class SitecoreRepository : ISitecoreRepository
{
    ISitecoreContext sitecoreContext = null;

    public SitecoreRepository(ISitecoreContext context)
    {
        this.sitecoreContext = context;
    }
}
控制器类:

public class HomeController : Controller
{
    private ISitecoreRepository _repository;
    public HomeController(ISitecoreRepository repository)
    {
        this._repository = repository;
    }
}
每次我运行项目Sitecore时,都会抛出一个错误,说明它无法创建类型为PoC.Quotes.Controllers.HomeController、PoC.Quotes.Controllers的控制器。我猜它显示了完全限定的名称,因为这就是我在控制器渲染中设置它的方式

第一个问题是控制器构造函数参数。我取出它并使用以下语句获取存储库的实例:

System.Web.Mvc.DependencyResolver.Current.GetService<ISitecoreRepository>();
然而,如果我进入Sitecore并将该属性更改为“仅在家”,那么一切都是好的。我甚至尝试过使用PoC.Quotes.Controllers.Home的临时版本,但仍然出现了一个错误,请注意另一个错误

不确定我是否做错了什么,但感觉有点奇怪


有没有办法解决这个问题?

虽然我不知道您的注册是如何配置的,但听起来您最好还是选择控制器工厂。温莎就是一个例子,但你可以很容易地在Unity中交换。为了不修改Global.asax,还可以使用WebActivatex连接引导启动

引导器

控制器厂


在这方面花了相当多的时间,并设法提出了一个解决方案。在这里写有点长,所以我把它放在了博客上

基本上,这不是Unity或其他DI容器的问题,而是Sitecore如何处理完全限定名。是的,我知道理想情况下,您不想使用这些名称,而是要遵循MVC模式,但我在博客文章中解释了为什么要使用完全限定的名称

作为高级解释,问题存在于两个Sitecore类ControllerRunner和SitecoreControllerFactory中。这两个类都包含一些方法,这些方法标识完全限定名,并使用反射调用无参数构造函数来实例化新实例。我应用的修复覆盖了这些方法来调用控制器工厂

谢谢你提供的帮助


安德烈你好,吉姆,谢谢你的回复。我的unity配置非常简单,添加了ISitecoreRepository接口和ISitecoreContext Glass映射器接口的配置。我之前曾尝试过温莎城堡工厂,如您在示例中所示,但也遇到了同样的问题。能否在引导代码中设置断点以验证Global.asax或WebActivator是否在Sitecore中工作?在对Sitecore.MVC进行了几个小时的反编译后,我得出结论,问题在于我在Sitecore中为控制器指定的名称。如果我只是用家作为名字,一切都是完美的。使用完全限定名后,Sitecore使用反射实例化新对象并查找无参数构造函数。我仍在研究它,因为它似乎是一个限制使用完全限定的名称,这是ASP.NETMVC相关的。任何帮助或想法都是正确的。对于Sitecore中的渲染,不应将控制器后缀添加到控制器字段a.k.a“无完全限定名”。
PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Site.Website.Cms.WindsorConfig), "RegisterComponents")]`
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Site.Website.Cms.WindsorConfig), "ReleaseComponents")]

/// <summary>
/// Provides a bootstrapping and resolving hook for dependency resolution for MVC, Web API, and service locator.
/// </summary>
public static class WindsorConfig
{
    private static Lazy<IWindsorContainer> _container;

    static WindsorConfig()
    {
        _container = new Lazy<IWindsorContainer>(() => BuildContainer());
    }

    public static IWindsorContainer WindsorContainer
    {
        get
        {
            return _container.Value;
        }
    }

    /// <summary>
    /// Generates and configures the container when the application is started.
    /// </summary>
    public static void RegisterComponents()
    {
        ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(WindsorContainer));
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorControllerActivator(WindsorContainer));
    }

    /// <summary>
    /// Disposes of the container when the application is shut down.
    /// </summary>
    public static void ReleaseComponents()
    {
        WindsorContainer.Dispose();
    }
}
/// <summary>
/// Provides controller dependency resolving for ASP.NET MVC controllers.
/// </summary>
public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer _container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        if (container == null) throw new ArgumentNullException("container");
        this._container = container;
    }

    public override void ReleaseController(IController controller)
    {
        this._container.Release(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)this._container.Resolve(controllerType);
    }
}