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


7

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;} 
}

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

回答:


1

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

メインビューpostはそのモデルを持ちます。このモデルは、で構成されますONLYこの記事を表示するのに必要なプロパティ(authortitlebody、など)。その後、のすべての部分post、あなたが(と考えることができるという見解timelinetag navigation panelsubscribing panel、など)は、独自のビューに分割されるだろうし、それぞれが独自のモデルを持っているでしょう。このようにして、必要なときにコントローラーでこれらのモデルを構築できます。

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

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


これは私が従おうとする一般的なアプローチです。私の質問は、これらの部分的なビューを独自のモデルと組み合わせる方法についてでした。それでも私はそれをより明確にするために質問を更新します。
Hedin 2013

1
わかりました...最初の混乱でごめんなさい。私は、必要なすべての部分ビューを個人的に格納するコンテナービューを使用します。
ethorn10 2013

1

私がしていることは、ポイント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つのアプローチの目的です。3つ目は、RenderActionまたは@ Html.Actionを呼び出すことだけです。これには、コントローラーメソッドの呼び出しが含まれます。返信ありがとうございます!
Hedin 2013

1
@ヘディンああ、わかりました...あなたのアプローチ#1は1つの大きな(異なる)ビューモデルを使用して、より「モノリシック」であると思いました。だから、はい、私は1を使用し、それが良いと思います。私も3番目のものが少ないのが好きですが、それはキャッシュに関しては良いです。パフォーマンスの問題がある場合、またはビューの一部をキャッシュする必要がある場合は、試してみる価値があります。
LorenzoDematté2013

部分ビューをスキップするのはどうですか?たとえば、ユーザーの役割に基づいていますか?
LifeH2O、2015年

0

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.