web-dev-qa-db-ja.com

MVC Webアプリケーションで複雑なビュー(複数の部分から構成される)を処理する方法

MVCパターンを使用してブログWebアプリケーションを作成しているとしましょう。ブログアプリケーションのメインページの一般的なレイアウトは、メインパーツにある種の投稿インデックスであり、それ以外に、タイムライン、タグナビゲーションパネル、サブスクライブパネルなどの追加パーツがあります。これらのコントロールは単一の投稿ビュー。他のビューに表示される場合があります。

私の質問は、ビューとコントローラーでこれらのパネルをどのように処理するかです。ここには3つのアプローチがあります。

  1. ビューのレンダリングに必要なすべての情報(インデックスまたは単一の投稿)を含む大きなviewmodelクラスを作成します。その場合、これらのサイドパネルを部分ビューにして、その大きなビューモデルの一部を渡してレンダリングされるビューから呼び出すことができます。欠点は、コードが重複していることを意味する、さまざまなコントローラーメソッド間でコードを埋めるviewmodelを使用することです。それはかなり悪いです。

  2. ビューレンダリングの別のレイヤーを作成します。たとえば、レンダリングの最上位レイヤーが、レンダリングされたHTMLの一部、または呼び出されたときにHTMLを出力する関数を受け取ります。この「結合パーシャルレイヤー」の下のレイヤーは、メインコンテンツを含め、必要な各パネルのパーシャルビューを提供します。ここの欠点-メモリ使用量。最新のフレームワークのほとんどは、HTMLを直接出力ストリームにレンダリングしますが、このアプローチでは、部分ビューが最初に文字列オブジェクトにレンダリングされ、メモリのオーバーヘッドが発生します。

  3. ビューからコントローラーメソッドを呼び出すasp.net mvcの「RenderAction」のようなものを使用します。これはMVCアプローチを落とすため、与えられた3の最悪のソリューションだと思います。

質問は特定のフレームワークに縛られているわけではありません。そのようなことを行う一般的な方法を理解したいと思います。

[〜#〜]更新[〜#〜]

答えが出た後、投稿が明確でないことがわかりました。ここで合理的な更新:

viewmodelという用語で、特定のビューのレンダリングに必要なすべてのデータを含むオブジェクトを理解しています。

3つのアプローチはすべて、独自のビューモデルを使用して部分ビューを構築することを含みます。例(C#構文を使用):

class SinglePostViewModel {
  string Text {get;set;}
  string Title {get;set;}
  string Slug {get;set;}
  DateTime PublishedDate {get;set;}
  ...
}

class TagNavigationPanelViewModel {
  string TagText {get;set;}
  int PostsCount {get;set;}
}

class CalendarNavigationPanelViewModel {
  DateTime YearAndMonth {get;set;}
  int PostsCount {get;set;} 
}

私の質問は、これらの部分的なビューをうまく組み合わせる方法です。

7
Hedin

あなたの投稿を誤解していない限り、言及されていない別の方法がわかります。

メインビューpostにはモデルがあります。このモデルは[〜#〜] only [〜#〜]で構成され、この投稿を表示するために必要なプロパティ(authortitlebodyなど)。次に、考えられるpostビューのすべての部分(timelinetag navigation panelsubscribing panelなど)は独自のビューに分割され、それぞれに独自のモデルがあります。このようにして、必要なときにコントローラーでこれらのモデルを構築できます。

これらをこのように分割するのは不必要な余分な作業のように聞こえるかもしれませんが、それは 単一責任の原則 に役立ちます。それぞれの「ビュー/モデル」に焦点を合わせておくと、必要な場所で再利用できます。

コードが自分自身を複製し始めていると感じた場合は、状況によって異なりますが、何らかの「ヘルパークラス」の作成を検討する必要があります。このヘルパークラスは、すべてのモデルビルドを1か所で処理し、他のすべての重複コードはヘルパークラス呼び出しに取り除かれます。

1
ethorn10

私がしていることは、ポイント1と3のバリエーション/組み合わせです。私は、コンテナーモデルでビューモデルを組み合わせ、それを「メイン」ビューモデルとして使用します。パーツをモデルとしてパーシャルに渡します。

あなたの例に従って、私はデフォルトのページのためにこのビューモデルを作成します:

class DefaultViewModel {
  public List<SinglePostViewModel> Posts ...
  public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  ...
}

Default.cshtml

@model DefaultViewModel
...html for rendering the default page...


@Html.Partial("_TagNavigationPanel", Model.Tags)
...etc...

_TagNavigationPanel.cshtml

@model TagNavigationPanelViewModel
...html+razor for rendering the tags...

次に、1つの投稿ページに対して同じアプローチに従います。

class SinglePostPageViewModel {
  public SinglePostViewModel Post ...
  // no tags in single view, for example..
  // public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  // But a list of related, perhaps?
  public List<RelatedPosts> RelatedPosts
  ...
}

そして、それに応じてビュー(cshtml(s))を構築します

1

SinglePostViewTagNavigationPanelViewおよびCalendarNavigationPanelViewの3つのサブビューすべてを含む単一の「コンテナ」ビューを作成できます。 SinglePostViewをページに必要な他のビューに置き換えることもできます。この方法では、さまざまなページの「中央」(投稿)ビューを別のタイプのビュー(たとえば、投稿のリスト)に置き換えるだけでよく、他のビューは対応するデータで置き換えるだけで、置き換える必要はありません。

コンテナービュー(たとえば、MyView)は、すべてのサブビューへの参照を保持する必要があります。異なるサブビューを更新するために使用される異なるupdateメソッドがある場合があります。例-updateCalendar(CalendarNavigationPanelViewModel calendarData)またはupdatePost(SinglePostViewModel postData)。または、単一のupdate(IViewModel modelData)-modelDataのタイプをチェック(およびキャスト)して、更新するビューを決定する必要があります

0
stan0