4

关于 ASP.NET MVC 3 中的一种多租户实现,我遇到了一个无法预料的问题。

假设我有 2 个网站:example.comexample.fr. 它们都由 IIS 中的同一个 MVC 网站提供服务。

然后我有一个自定义VirtualPathProvider,它基于域,为来自不同位置的视图提供服务。控制器总是相同的,只是从不同的位置获取视图。

这一切都很好。问题来自 ASP.NET View 编译。假设两个域都有一个具有相同名称和路径的视图(为清楚起见,MVC 视图路径):

example.com/Views/MyController/Index.cshtml
example.fr/Views/MyController/Index.cshtml

这应该运作良好。但是 ASP.NET BuildManager(将 Razor 代码编译为程序集)仅基于 Virtual Path缓存构建。

所以这意味着当我在访问时第一次渲染视图时,example.com我得到了正确的视图。但是,如果我尝试在 的上下文中渲染视图example.fr,ASP.NET 会认为该视图没有被修改(这是真的,因为虚拟路径是相同的)并且它将从缓存中执行视图,因此渲染不正确看法。

解决它的一种方法是根据域在不同的命名空间中编译视图。

到目前为止,我得到了MvcWebRazorHostFactory,覆盖CreateHost方法以返回RazorEngineHost具有正确命名空间的 a。不确定它是否会起作用,因为我认为我当时没有所有需要的信息(HttpContext是其中之一)

有人有什么想法吗?我在这里遗漏了一些明显的东西吗?

谢谢

4

2 回答 2

2

好的,事实证明很容易解决。

我所要做的就是覆盖GetCacheKey我的VirtualPathProvider并返回一个考虑到主机名的密钥字符串。

在我的情况下,我只是连接主机和虚拟路径并返回结果字符串的哈希码。

于 2012-07-24T11:39:51.083 回答
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)缓存结果。它还允许我使用自己的路径形式来搜索视图,因此我可以:

如果我想覆盖视图的一部分,Views/Controller/Action.cshtml 或 Views/Custom/[client]/Controller/Action.cshtml(或非常小的部分)。

抱歉,它并没有真正回答您的具体问题,但它有帮助吗?如果您对这种方法感兴趣,我可以提供更多代码。

于 2012-07-24T10:25:55.863 回答