2011-08-04 14 views
0

私は現在、多くの共通点がありますが、別々のパッケージとしてデプロイされている一連のMVC3 Webアプリケーションを開発中です。 1つの例外として、インストールごとに配備される管理アプリケーションがあります。また、データベースと共通エンティティのセットを共有します。MVC3コントローラとビュー再利用性

最近追加されたものには、認証(カスタマイズされたフォーム認証)、自動化されたメニュービルディング(コントローラーアクション属性を使用)、その他ほとんどの画面が含まれていました。私がこれらの問題を抱えているのは、コントローラとビューを二重化しなければならないということです。

認証ビットが最も良い例です。各アプリケーションには、アカウントコントローラと認証ビューがそれぞれのコピーとして存在するようになりました。より多くのアプリケーションが追加されているので、これがいかにしてメンテナンスの悪夢になっているかを見ることができます。もう1つの例は、メニューをレンダリングする各アプリケーションの共有ビューです(通常はHtml.Action経由で呼び出されます)。これには、それぞれのアプリケーションでまったく同じように見えるコントローラも必要です。

認証とメニュー作成の実装の詳細を、共通のhtmlHelper拡張機能とMvc Web固有のものを持つXXX.Core.Mvcという共有プロジェクトに抽象化することができました。したがって、アプリケーション内の複製されたビューとコントローラはすべて、プロキシとして機能します。

これらを取り除くための良いパターンを探しています。そのため、共通のビューとコントローラは、参照/呼び出し可能な共有プロジェクトに常駐します。誰もこれのような何かをしましたか?良い記事や例をお勧めできますか?

たとえば、View ActionResultを返すコントローラアクションが、別のプロジェクトまたは共有パスのビューにどのように向いていますか?たとえば、/ Account/Authenticateを別のプロジェクトのコントローラにルーティングする方法は?展開の意味は何ですか?

+0

[この投稿](http://blogs.msdn.com/b/webdevtools/archive/2011/01/20/how-to-get-razor-intellisense-for-model-in-a-class- library-project.aspx)は便利です。再利用可能なカスタムエラーを今実装しようとしています。 –

答えて

0

私は2つのことを試しました。いずれの場合も、共通コントローラとビューは個別のアセンブリに配置されていました。概念の証明のために、共通のアプリケーションエラー処理を実装しました。だから私のエンドポイントMvc3アプリケーションでは、Global.asaxのは実装しています。アプリケーションのエラーハンドラが別のアセンブリで実装されて

protected void Application_Error() 
{ 
    ApplicationErrorHandler.Get().Handle(Server, new HttpResponseWrapper(Response), new HttpContextWrapper(Context)); 
} 

:コントローラのフォルダにこの同じアセンブリで

public class ApplicationErrorHandler 
{ 
    public static ApplicationErrorHandler Get() 
    { 
     return new ApplicationErrorHandler(); 
    } 

    public void Handle(HttpServerUtility server, HttpResponseBase response, HttpContextBase context) 
    { 
     var exception = server.GetLastError(); 
     var httpException = exception as HttpException; 
     response.Clear(); 
     server.ClearError(); 
     var routeData = new RouteData(); 
     routeData.Values["controller"] = "Errors"; 
     routeData.Values["action"] = "Http500"; 
     routeData.Values["exception"] = exception; 
     response.StatusCode = 500; 
     if (httpException != null) 
     { 
      response.StatusCode = httpException.GetHttpCode(); 
      switch (response.StatusCode) 
      { 
       case 403: 
        routeData.Values["action"] = "Http403"; 
        break; 
       case 404: 
        routeData.Values["action"] = "Http404"; 
        break; 
      } 
     } 
     IController errorsController = new ErrorsController(); 
     var rc = new RequestContext(context, routeData); 
     errorsController.Execute(rc); 
    } 
} 

がErrorsControllerとビューを常駐します\ Errorsには3つのビューが必要です。 Http403.cshtml、Http404.cshtmlおよびHttp405.cshtml。構造は通常のMvc3プロジェクトと同じです。しかし、@ modelサポートとintelisenseを動作させるためには、通常のプロジェクトのViewsからのファイルのコピーであるweb.configが必要であり、この別のアセンブリのビューの下に置かれます。

アプリケーションでエラーが発生した場合(httpステータス500 - 内部サーバーエラー)、ErrorsControllerが実行され、この場合に使用されるビューはHttp500.cshtmlになります。パスは次のようになりますに見えた:

  • 〜\エラー\ビュー\ Http500.cshtml
  • 〜\ビュー\共有\ Http500.cshtmlアセンブリ私が試したからファイルを供給するためには

2つのこと:

アプローチ1:VirtualPathProviderを実装します。私は詳細には触れませんが、目標はcshtmlビューをリソースとして埋め込み、VirtualPathProviderとVirtualFileを使ってそれらを提供することです。このアプローチの問題は、Razorにビューを評価させるためにViewsフォルダからweb.configをサーバーに実行する方法が見つからないということです。ファイルを取得してストリームすることはできますが、実行することはできません。問題が何だったか説明するために、Http500.cshtml考える:返された何

@model Exception 
<h3>@MvcHtmlString.Create(Model.Message.Replace(Environment.NewLine, "<br />").Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"))</h3> 
<p>@MvcHtmlString.Create(Model.StackTrace.Replace(Environment.NewLine, "<br />").Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"))</p> 
<input type="hidden" name="serverError" value="true"/> 

すると、ファイルの内容ではなく、評価の例外でした。その理由は、Razorが使用されるように、Viewフォルダのweb.configも提供する必要があるからです。デフォルトでは、ビューエンジンはWebフォーム(.aspx)です。

アプローチ2:IISで仮想ディレクトリを作成します。ビューはリソースとしてコンパイルする必要がないため、仮想化の必要はないため、このアプローチははるかに優れています。必要なのは、私の最終アプリケーションのビューフォルダの下に仮想ディレクトリのエラーを作成し、それが共通アセンブリのViews \ Errorsがどこに配置されているかを指すことだけでした。

確かに、一般的なファイルは.dllから分離されている必要があるので、適切なプラグインのようには動作しませんが、私はあまり気にしません。

しかし、誰かが仮想ファイルをRazorで動作させる方法を知っていれば、私はすべて耳にします。まあ、本当にすべての目。

関連する問題