6

MVC プロジェクトの領域の名前を取得する方法はありますか?

ここに私が考えることができるいくつかの方法があります:

a) ソースがあれば、プロジェクト フォルダー構造をブラウズして、Areas フォルダーの下のフォルダーを列挙できます。ただし、各サブフォルダーの下に Controllers フォルダーと Views フォルダーも列挙しない限り、すべてのフォルダーが領域を表しているとは限りません。お分かりのように、このアプローチは最悪です。

b) バイナリから、条件に一致するすべての名前空間を列挙できましたRootNamespaceOfProject.Areas.*

または、もっとエレガントな方法があると確信しています。ASP.NET MVC フレームワークには、すべての領域の記録を保持するディクショナリが必要です。

次に、MVC フレームワークには、領域を表すプログラム構造もありますか? 見つからないようです。領域に関連する構成要素は 4 つだけです。

 1. AreaRegistration
 2. AreaRegistrationContext
 3. IRouteWithArea
 4. AreaHelpers (an internal class)

ある場合、たとえば、その領域内のすべてのコントローラーを列挙することは可能でしょうか?

編集済み

MVC-AreaRegistrationTypeCache.xml\Windows\Microsoft.NET\Framework\v4.xx\Temporary ASP.NET Files\root\RandomlyGeneratedHash1\RandomlyGeneratedHash2\UserCache フォルダーにこのファイルが呼び出されていることに気付きました。

このフォルダーには 2 つのファイルがあります。

a) MVC-AreaRegistrationTypeCache.xml : このファイルには、領域を持つマシン上のすべてのアセンブリ内のすべての領域のリストが含まれています。

b) MVC-ControllerTypeCache.xml : このファイルには、アセンブリの領域内のコントローラーが一覧表示されます。

ここで確認すべき唯一のことは、MVC フレームワークにこれらのファイルを読み取らせ、特定の領域がバイナリに存在するかどうかを知らせるプログラム的な方法があるかどうかです。

私はクラスがそのAreaRegistrationクラスかもしれないと考えています。さらに調べてみると…

4

3 に答える 3

6

プロジェクトに登録されているルートを取得できる唯一の方法は、AreaRegistration を継承するタイプのプロジェクトを列挙することです。現在登録されているエリアを追跡するオブジェクト プライベートまたはパブリックはないようです。

長い説明が続きます...

ここで留意すべきハードルの 1 つは、領域は、任意の文字列と名前空間のリストを結合したものに過ぎないということです。エリアが登録されると、一意の「エリア」DataToken によって識別可能ないくつかの新しいルールを使用して、アプリケーションのルート コレクションが拡張されるだけです。

領域を登録するプロセスを見ると、System.Web.Mvc.AreaRegistrationから継承し、 RegisterArea()をオーバーライドする必要があります。RegisterArea() は、エリア名、ルート コレクション、およびオブジェクトの状態を定義するAreaRegistrationContextを受け取りますが、RegisterArea() を実装するための形式を確認すると、void を返し、コンテキスト オブジェクトを保持するために何もしません。さらに、RegisterArea() が起動される前に実行されるコード (Reflector) を見ると、RegisterArea() に渡される AreaRegistrationContext オブジェクトが永久に追跡されないことがわかります。

internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state)
{
    foreach (Type type in TypeCacheUtil.GetFilteredTypesFromAssemblies("MVC-AreaRegistrationTypeCache.xml", new Predicate<Type>(AreaRegistration.IsAreaRegistrationType), buildManager))
    {
        ((AreaRegistration) Activator.CreateInstance(type)).CreateContextAndRegister(routes, state);
    }
}

internal void CreateContextAndRegister(RouteCollection routes, object state)
{
    AreaRegistrationContext context = new AreaRegistrationContext(this.AreaName, routes, state);
    string str = base.GetType().Namespace;
    if (str != null)
    {
        context.Namespaces.Add(str + ".*");
    }
    this.RegisterArea(context);
}

ご覧のとおり、静的メソッドRegisterAllAreas()を呼び出すと internal が呼び出さRegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state)れ、次にinternal が呼び出され、internal が呼び出さCreateContextAndRegister(RouteCollection routes, object state)れて AreaRegistrationContext が作成され、それが に渡されRegisterArea()ます。

私が知る限り、永続的に保存された各エリアに対して作成された AreaRegistrationContext は、どの時点でも決してありません。

于 2010-09-01T16:36:10.543 に答える
1

MVC が行っていることを実行し、参照されているすべてのアセンブリを反復処理して、から継承するクラスを探すことができますAreaRegistration。その後、簡単に取得できますAreaRegistration.AreaName

Twitter Bootstrapを使用してトップレベルのナビゲーションバーを構築するためにこれを行うことを計画しています。

于 2012-03-06T08:50:08.313 に答える
1

このスレッドは答えを見つけるのに役立ちましたが、ここで明示的に投稿した人は誰もいませんでした。これが私が思いついたものですが、すべての領域が同じアセンブリ内にあるかどうかによっては、調整が必要になる場合があることに注意してください。

private IEnumerable<AreaRegistration> GetAllAreasRegistered()
{
    var assembly = this.GetType().Assembly;
    var areaTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(AreaRegistration)));
    var areas = new List<AreaRegistration>();
    foreach (var type in areaTypes)
    {
        areas.Add((AreaRegistration)Activator.CreateInstance(type));
    }
    return areas;
}
于 2013-11-15T22:40:10.513 に答える