我对ASP.NET MVC 3中的一种多租户实现有一个无法预见的问题。
假设我有2个网站:example.com
和example.fr
。它们都由IIS中的同一个MVC网站提供服务。
然后我有一个自定义VirtualPathProvider
,基于域,提供来自不同位置的视图。 Controller始终相同,只从不同位置获取视图。
这一切都运作良好。 ASP.NET View编译带来了问题。假设两个域都具有相同名称和路径的视图(为清晰起见,MVC视图路径):
example.com/Views/MyController/Index.cshtml
example.fr/Views/MyController/Index.cshtml
这应该运作良好。但ASP.NET BuildManager(将Razor代码编译为程序集)缓存仅基于虚拟路径的构建 。
所以这意味着当我在访问example.com
时首次渲染视图时,我得到了正确的视图。但是,如果我尝试在example.fr
的上下文中呈现View,则ASP.NET认为视图尚未被修改(因为虚拟路径是相同的),它将从缓存执行视图,因此呈现不正确的视图。
解决问题的一种方法是,可能会根据域在不同的命名空间中编译视图。
到目前为止,我已经到了MvcWebRazorHostFactory
,覆盖CreateHost
方法以返回具有正确名称空间的RazorEngineHost
。不确定它是否会起作用,因为我觉得我当时没有所需的所有信息(HttpContext
就是其中之一)
任何人都有任何想法?我错过了一些明显的东西吗?
由于
答案 0 :(得分:2)
好的,结果很简单。
我所要做的只是覆盖GetCacheKey
中的VirtualPathProvider
并返回一个考虑了主机名的密钥字符串。
在我的情况下,我只是简单地连接主机和虚拟路径,并返回结果字符串的哈希码。
答案 1 :(得分:1)
我不知道你是否已经走过这条路太远而无法考虑其他方法,但我也有一个我正在开发的多租户系统,我通过覆盖视图引擎来完成它,基于Razor。
public class MultiTenancyRazorViewEngine : RazorViewEngine
{
/// <summary>
/// Finds the specified partial view by using the specified controller context.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="partialViewName">The name of the partial view.</param>
/// <param name="useCache">true to use the cached partial view.</param>
/// <returns>The partial view.</returns>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext"/> parameter is null (Nothing in Visual Basic).</exception>
/// <exception cref="T:System.ArgumentException">The <paramref name="partialViewName"/> parameter is null or empty.</exception>
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
var searchedLocations = new List<string>();
var foundFile = Support.ResolvePath(string.Format("{0}.cshtml", partialViewName), controllerContext.HttpContext, controllerContext.RouteData, searchedLocations);
return foundFile == null
? new ViewEngineResult(searchedLocations)
: base.FindPartialView(controllerContext, foundFile, useCache);
}
/// <summary>
/// Finds the view.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="viewName">Name of the view.</param>
/// <param name="layoutPath">The layout path.</param>
/// <param name="useCache">if set to <c>true</c> [use cache].</param>
/// <returns></returns>
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string layoutPath, bool useCache)
{
var searchedLocations = new List<string>();
var foundFile = Support.ResolvePath(string.Format("{0}.cshtml", viewName), controllerContext.HttpContext, controllerContext.RouteData, searchedLocations);
return foundFile == null
? new ViewEngineResult(searchedLocations)
: base.FindView(controllerContext, foundFile, layoutPath, useCache);
}
我有自己的支持方法来查找视图:“ResolvePath”。我使用HttpContext,因为我已经存储了被访问的站点(通过主机名),并根据该主机名(或客户端的唯一ID)缓存结果。它还允许我使用自己的路径来搜索视图,所以我可以:
视图/控制器/ Action.cshtml 要么 Views / Custom / [client] /Controller/Action.cshtml(或者非常小的部分) 如果我想覆盖视图的一部分。
抱歉,它并没有真正回答您的具体问题,但它有帮助吗?如果您对这种方法感兴趣,我可以提供更多代码。