我正在尝试建立一个全新的Sitecore 7.2网站,我希望将MVC 5, Glass Mapper和Microsoft Unity集成为DI容器,Sitecore不想玩得很好。
我的场景是这样的:
- 得到了一个名为PoC.Quotes.Web的Web项目-这将只包含CSS, HTML和任何其他资产,没有控制器
- 获得了一个名为PoC.Quotes.Controllers的类库项目-这只包含controllers
- 获得了一个名为PoC.Quotes.DataLayer的类库项目-它包含一个接口SitecoreRepository和它的具体实现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>();
结果是空的,因为类SitecoreRepository只有一个构造函数和一个参数,它不会被实例化。一旦我把这个参数也排除了,那么一切就都很好了。
然而,对我来说,这有点违背了使用DI容器的目的。
我试着看温莎城堡,但是尽管网上有更多的文档,没有任何工作,因为我得到类似的问题。
这有点烦人,因为如果我在一个基本的MVC 5应用程序中运行类似的测试(我这样做只是为了确保我不会发疯),所有工作在不到5分钟。
任何想法?
编辑:在一个有趣的转折中,在这个问题上花了几个小时之后,我注意到实际上Unity或Windsor容器都可以很好地工作,但有一个限制……一个大的。
在我的控制器渲染中,我将控制器属性设置为控制器的完全限定名称:
PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers
然而,如果我进入Sitecore并将该属性更改为Home,神奇的是一切都很好。我甚至尝试过使用PoC.Quotes.Controllers.Home的临时版本,但仍然得到一个错误,另一个请注意。
不知道我是否做错了什么,但感觉有点奇怪。
有什么办法可以解决这个问题吗?
虽然我不知道您的注册是如何配置的,但听起来您可能更适合使用控制器工厂。以《Windsor》为例,但你可以轻松地在Unity中进行交换。这样你就不会修改全局。此外,你还可以使用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();
}
}
<<p> 控制器工厂/strong> /// <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);
}
}
在这个问题上花了相当多的时间,并设法想出了一个解决方案。写在这里有点长,所以我把它放在一个博客文章http://agooddayforscience.blogspot.co.uk/2015/10/sitecore-multi-tenancy-and-di-containers.html
基本上这不是Unity或其他DI容器的问题,而是Sitecore如何处理完全限定名称的问题。是的,我知道理想情况下你不想使用这些,而是遵循MVC模式,但我已经在博客文章中解释了为什么使用完全限定名。
作为一个高层次的解释,问题存在于2个Sitecore类ControllerRunner和SitecoreControllerFactory。这两个类都包含一些方法,用于标识完全限定名称,并使用反射调用无参数构造函数来实例化新实例。我所应用的修复程序覆盖了这些方法来调用控制器工厂。
感谢您提供的所有帮助。
安德烈