14

Asp.Net MVC 4 プロジェクトで 404 応答を解決できません。4.5 をターゲットとする VS2012 に組み込まれています。

スタンドアロンの DLL に組み込まれた、コンパイル済みのビューとコントローラーがあります。DLL を動的にロードして、コア プロジェクトからそれらを調べることができます。それらのメソッドを呼び出すこともできます。ただし、MVC フレームワークはコントローラーを認識していないようです。私はここに近づいていますが、何かが欠けています。

コントローラーとビューの背景

コントローラーは、スタンドアロン MVC プロジェクトに組み込まれ、から継承されControllerます。そこにはあまり興味深いことはありません。ビューは RazorGenerator を使用し、プロジェクトに存在するクラスになります。

プロジェクトの出力は、コントローラーとビューを正しく含む DLL です。

IPluginDLLは、ライブラリ内の別のクラス (コントローラーの一部ではない) で、特定のインターフェイスを実装します。これを と呼びます。

DLL のロード

Visual Studio で管理者として実行し、IIS でホストされているアプリをコンパイルします。プロジェクトをビルドしたら、プラグイン DLL を "Plugins" ディレクトリにドロップします。デバッグせずに (これは後で重要になります)、IE を開いてサイトに移動します。 この時点でアプリはビルドされていますが、実行されることはないため、起動イベントが発生することに注意してください。アプリ プールをリサイクルしても、ここにあるものはすべて一貫しています。

2 つのメソッドを持つStartupクラスがあり、PreStartととをそれぞれPostStart使用してメソッドを呼び出します。WebActivator.PreApplicationStartMethodWebActivator.PostApplicationStartMethod

PreStart私が次のことをする場所です:

  • "Plugins" ディレクトリにあるすべてのプラグイン DLL のリストを取得する
  • すべてのプラグインをコピーしますAppDomain.CurrentDomain.DynamicDirectory
  • 型をロードします... IPluginI が含まれている場合
    • アセンブリを BuildManager に追加する
    • IPlugin を実装するクラスでいくつかのメソッドを呼び出します

「PostStart」では、次のコードを実行します (RazorGenerator.Mvc のコードに基づく):

foreach (var assembly in Modules.Select(m=>m.Value))
{
    var engine = new PrecompiledMvcEngine(assembly)
    {
        UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
    };

    ViewEngines.Engines.Insert(0, engine);
    VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}

Modulesこのコンテキストでは、値が読み込まれたアセンブリであるキーと値のペアです。このコードの目的は、ビューを解決する方法を認識しているアセンブリごとにビュー エンジンを追加することで、MVC がビューを認識できるようにすることです (これは RazorGenerator の一部です)。

私が近くにいることをどのように知るか (しかし明らかに葉巻が欠けている)

IPluginRegisterRoutesご想像のとおり、インターフェイスを実装する人のためにルートが登録される場所と呼ばれるメソッドを定義します。このメソッドを呼び出すPreStartと、ルートが追加されます - これらがルート テーブルに存在することを確認しました。たとえば、プラグインで定義されたルートで、メソッドの動的呼び出しによって作成され、PreStartルートを調べると、次のようなものが DataToken として表示されます。

Namespaces = Plugin.Name.Controllers

ルートが登録され、アセンブリが読み込まれ、DLL が AppDomain の DynamicDirectory に正しくコピーされていることを確認しました。実行時に動的にロードされるクラスのメンバーを呼び出すことができます。しかし、ルートに一致する URL に移動すると、 404 が返されます。これは「ビューが見つかりませんでした」YSOD ではなく、コントローラーがまったく見つからないことに似ています。

これが私を混乱させる部分です。この時点で何もせずに Visual Studio に戻って F5 キーを押すと、すべてが機能します。

Visual Studio が何らかの方法で私が識別できないコントローラーを認識するようになり、MVC フレームワークがそれを認識しているようです。

最後に、質問

何が足りないのですか? MVC フレームワークにコントローラーを認識させるにはどうすればよいですか?

そして、この時点で、まだこれを読んでいるなら、ありがとう。:)

4

3 に答える 3

8

これはAsp.Net自体のバグであることが判明しました。

Asp.NetチームのEilonLiptonと問題について話し合い、これがMVCフレームワークで何か間違っていると考えた後、Eilonといくつかのチームメンバーは物事を掘り下げ、この会話ではエラーがより低いレベルにあることを発見しました:http: //aspnetwebstack.codeplex.com/discussions/403529

彼らはまた、BuildManagerへの呼び出しの後に別の呼び出しを含む回避策を提案しましたAddReferencedAssembly。これは、次のコードを介して実装しました。

    // Add the plugin as a reference to the application
    BuildManager.AddReferencedAssembly(assembly);
    BuildManager.AddCompilationDependency(assembly.FullName);

これにより、アプリケーションの初期化段階で、起動時にコントローラー/コンパイル済みビューを追加できます。私が今していることは、プラグインディレクトリ内のDLLのリストをループして、BuildManager上記のようにそれらをプッシュすることです。

ここでの唯一の制限は、アセンブリを削除したり、キャッシュを動的にクリアしたりできないことです。これを行うために私が見つけた唯一の方法は、参照されているアセンブリとコンパイルの依存関係に、これまで不明だったアセンブリを追加することです。アプリケーションの初期化中に新しいアセンブリを動的に発行することを実験しているので、新しいアセンブリを偽造することで、常に効果的にキャッシュをクリアし、以前に含まれていたプラグインを削除できます。

これが他の誰かに役立つことを願っています。

乾杯。

于 2013-03-04T16:29:03.907 に答える
1

この問題のように見えます:

MVC は、ビュー エンジンのアセンブリ修飾型名を使用して、異なるビュー エンジンからのビュー キャッシュ エントリを明確にします。そのため、複数の PrecompiledMvc​​Engine オブジェクトを持つことはできません (複数のアセンブリでビューをプリコンパイルした場合のように)。この問題は、アセンブリごとに PrecompiledMvc​​Engine から別の派生クラスを作成することで解決できます。または、アセンブリから何らかの型でパラメーター化された単一のジェネリック派生クラスを作成することによって。

記事はこちら.

于 2013-02-21T17:49:25.813 に答える
0

@MisterJames、これを見てください:

Asp.Net Mvc プラガブル アプリケーション

役に立つことを願っています。

于 2013-02-21T19:21:14.577 に答える