Sitecore DI with Unity

时间:2015-10-08 15:27:41

标签: 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的类库项目 - 它包含一个接口ISitecoreRepository,它的具体实现SitecoreRepository

SitecoreRepository类有一个构造函数,它接收1个单一参数,Glass Mapper Context,我的一个控制器在构造函数中接收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>();

结果为null,因为SitecoreRepository类只有1个带有1个参数的构造函数,并且它不会被实例化。一旦我得到了这个参数,那么一切都很好。

然而,对我而言,这种方式违背了拥有DI容器的目的。

我曾尝试过看温莎城堡,但是虽然网上有更多文档,但没有任何作用,因为我遇到了类似的问题。

这有点烦人,因为如果我在一个基本的MVC 5应用程序中运行类似的测试(我这样做只是为了确保我不会发疯),所有这些都可以在不到5分钟内正常运行。

有什么想法吗?

修改

有趣的是,在这个问题花了几个小时之后,我注意到Unity或Windsor容器实际上只有一个限制......一个很大的限制。

在我的控制器渲染中,我将控制器属性设置为控制器的完全限定名称:

PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers

然而,如果我进入Sitecore并将该属性更改为Home,那么魔术一切都很好。我甚至尝试过使用PoC.Quotes.Controllers.Home的临时版本,但仍然会收到错误,另外一个会介意你。

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

任何想法如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

虽然我无法确定您的注册配置如何,但听起来您可能会更好地使用控制器工厂。示例是Windsor,但您可以轻松地在Unity中交换。因此,您不需要修改Global.asax,您也可以使用WebActivatorEx连接引导启动。

<强>引导程序

[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);
    }
}

答案 1 :(得分:0)

花了相当多的时间并设法提出解决方案。写在这里有点长,所以我把它放在博客http://agooddayforscience.blogspot.co.uk/2015/10/sitecore-multi-tenancy-and-di-containers.html

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

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

感谢您提供的所有帮助。

安德烈