長い投稿は申し訳ありません。質問があります。ただ我慢してください。
少しのコンテキスト
私たちは、さまざまなユーザー設定、ユーザーが所属するグループ、ユーザーの出身地などに基づいて大幅に適応する必要があるサイトを持っています。以前はページのモデルに関連ビットを含めていたため、ページに、ユーザーが特定の年齢を超えているかどうかを示すテーブルがある場合、モデルでは次のようにします。
//model
public PageModel
{
public bool ShowTable {get;set;}
}
//controller
public PageController
{
public ActionResult ShowPage()
{
var model = new PageModel() {
ShowTable = User.Age > 21
};
return View(model);
}
}
//view
@if(Model.ShowTable)
{
<table>Some Html here</table>
}
これは、どのユーザーに何を表示すべきかを知るためにすぐに非常に複雑になりました。この問題に対処するために、特定のものが表示または非表示になるタイミングに関するすべてのロジックを一元化しました。このクラスを呼び出したUserConfiguration
ところ、(ほとんどの場合)何を表示すべきかを示すブール値を返す一連の関数が含まれていました。これにより、ユーザーに表示する必要がある一連の仕様とテストを設定できました。UserConfigratuion
次に、これは、すべてのページモデルが継承する必要がある基本クラスに配置されました。そのため、現在、次のようになっています。
//UserConfiguration
public UserConfiguration
{
private readonly User _user;
public UserConfiguration(User user) {
_user = user
}
public bool ShowTable() {
return _user.Age > 21;
}
}
//model base
public ModelBase
{
public UserConfiguration {get;set;}
}
//model
public PageModel : ModelBase
{
// whatever data is needed for the page
}
//controller
public PageController
{
public ActionResult ShowPage()
{
var userConfiguration = new UserConfiguration(User);
var model = new PageModel {
UserConfiguration = userConfiguration
};
return View(model);
}
}
//view
@if(Model.UserConfiguration.ShowTable())
{
<table>Some Html here</table>
}
これは主に、ユーザーが表示すべきものと表示すべきでないものの一連のテストを作成できるようになったために役立ちました。しかし、この追加のクラスをまとめてモデルに含める必要があるため、あまりクリーンなソリューションではありません。また、部分ビューのレンダリングにも影響があります。モデルにプロパティIEnumerable<Foo> Foos
があり、パーシャルでレンダリングしたいが、そのパーシャルもユーザー設定に依存している場合、問題があります。パーシャルはにアクセスできないため、モデルとしてパーシャルにfoosを渡すことはできませんUserConfiguration
。したがって、この情報にアクセスするための最良の方法は何でしょうか。私の見たところ、asp.net MVCのコンテキストでは、4つの方法が利用できます。
1)パーシャルなどの新しいモデルを用意する
// parent view
@{
var foosModel = new foosModel {
Foos = Model.Foos,
UserConfiguration = Model.UserConfiguration
}
}
@Html.RenderPartial("FooList", foosModel)
// child partial view
@if(Model.UserConfiguration.ShowTable) {
foreach(var foo in Model.Foos) {
//Some HTML
}
}
これはおそらく「最も純粋な」ソリューションであり、MVCの原則に最も忠実に従いますが、多くの(おそらく不必要な)モデルを含み、プロジェクトの肥大化を引き起こします。
2)ViewDataを介してUserConfigurationを公開します。例:
// parent view
@Html.RenderPartial("FooList", Model.Foos, new ViewDataDictionary { { "UserConfiguration", Model.UserConfiguration } })
// child partial view
@{
var userConfig = (UserConfiguration)ViewData["UserConfiguration"];
}
@if(userConfig.ShowTable) {
foreach(var foo in Model) {
//Some HTML
}
}
これはタイプセーフではなく、ViewDataから取得するために魔法の文字列に依存しているので、私は本当にこれが好きではありません。
3)UserConfigurationをViewBagに配置します。上記と同じ問題は本当に
4)ページモデルを変更し、http: //haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-viewのように、ページ自体のプロパティを介してUserConfigurationを公開します。.aspx /
UserConfigurationはアンビエントコンテキスト情報であるため、上記のオプション4のようにクラスを介して公開することは理にかなっています。この種のデータを公開するためにMVCで一般に受け入れられているベストプラクティスはありますか?誰かが過去にオプション4のようなことを試みたことがありますか?
tl; dr:一般的なMVCまたは特にasp.net MVCで、コンテキスト情報をサイトのビューに公開する最良の方法は何ですか?