4

ASP.NET MVC 3 での一種のマルチ テナンシーの実装に関して、予期しない問題が発生しました。

と の 2 つの Web サイトがあるexample.comとしexample.frます。どちらも IIS の同じ MVC Web サイトによって提供されます。

VirtualPathProvider次に、ドメインに基づいて、さまざまな場所からビューを提供するカスタムがあります。コントローラーは常に同じで、ビューのみが異なる場所から取得されます。

これはすべてうまくいきます。この問題は ASP.NET View のコンパイルで発生します。両方のドメインに同じ名前とパス (わかりやすくするために 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はその1つです)

誰にもアイデアはありますか?ここで明らかな何かが欠けていますか?

ありがとう

4

2 に答える 2

2

わかりました、解決するのは簡単です。

私がしなければならなかったのはGetCacheKey、 my をオーバーライドして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 に答える