2012-07-24 26 views
4

我有一個關於在ASP.NET MVC一種多租戶執行3.MVC 3多租戶和查看編譯緩存問題

說我有2個網站無法預料的問題:example.comexample.fr。它們都由IIS中的相同MVC網站提供服務。

然後我有一個自定義VirtualPathProvider,基於域,從不同的位置提供視圖。控制器總是相同的,只有視圖從不同的位置獲取。

這一切都很好。這個問題伴隨着ASP.NET視圖編譯。假設兩個域具有相同的名稱和路徑的視圖(MVC爲清楚起見意見路徑):

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

這應該很好地工作。但是ASP.NET BuildManager(將Razor代碼編譯爲程序集)緩存了僅基於虛擬路徑的內部版本

所以這意味着當我第一次訪問example.com時,我得到了正確的看法。但是,如果我嘗試在example.fr的上下文中呈現視圖,則ASP.NET認爲視圖未被修改(虛擬路徑相同,這是真實的),並且它將從緩存執行視圖,因此呈現錯誤的視圖。

解決這個問題的一種方法是根據域名在不同的命名空間中編譯視圖。

到目前爲止,我得到了MvcWebRazorHostFactory,覆蓋CreateHost方法返回一個RazorEngineHost與正確的命名空間。不知道它是否會工作,因爲我不認爲我在那一點上有所有需要的信息(HttpContext是其中之一)

任何人有任何想法?我在這裏錯過了很明顯的東西嗎

感謝

回答

2

好吧,結果很簡單。

我所要做的只是在我的VirtualPathProvider中覆蓋GetCacheKey並返回一個考慮主機名的密鑰字符串。

在我的情況下,我只是串聯主機和虛擬路徑並返回結果字符串的哈希碼。

+0

嗨,佩德羅,你可以把這段代碼放在Gist或在線的地方嗎?我正在努力尋找第二個租戶的虛擬路徑時編譯錯誤,它看起來像你可能有它排序 - 也許這只是這個CreateHost我需要擔心,雖然... – mcintyre321 2012-11-29 09:33:58

+0

我認爲這是絕對CreateHost,作爲我按照描述重寫了GetCacheKey,並且可以從我的租戶加載js文件,這只是它正在努力的xshtml。 – mcintyre321 2012-11-29 15:51:59

+0

這個概念的缺點是,當請求每個域的頁面時,您將失去之前完成的緩存。所以基本上你失去了緩存編譯視圖的好處。有沒有更好的解決方案,允許框架在第一次加載後仍然緩存每個單獨的視圖? – 2013-03-22 03:32:56

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,因爲我已經存儲了正在訪問的站點(通過主機名),並根據該主機名(或客戶端的唯一標識符)緩存結果。這也讓我做我自己的路徑表單搜索視圖,這樣我就可以有:

查看/控制器/ Action.cshtml 或 查看/自定義/ [客戶] /Controller/Action.cshtml(或者真的非常小的部分) 如果我想覆蓋視圖的一部分。

對不起,它沒有真正回答你的具體問題,但它有幫助嗎?如果你對這種方法感興趣,我可以提供更多的代碼。

+0

感謝你的想法,它也會工作得很好。我找到了適合我的特殊情況的標準解決方案,並在以上供以後參考。 – Pedro 2012-07-24 11:41:24