Bitte entschuldigen Sie den langen Beitrag. Es gibt eine Frage, nimm sie einfach mit.
Ein kleiner Kontext
Wir haben eine Site, die sich aufgrund einer Vielzahl von Benutzereinstellungen, der Gruppe, zu der der Benutzer gehört, woher sie kommen und anderen Dingen erheblich anpassen muss. Früher haben wir die relevanten Bits in das Modell für die Seite aufgenommen. Wenn die Seite also eine Tabelle enthält, aus der hervorgeht, ob der Benutzer älter als ein bestimmtes Alter ist, haben wir auf dem Modell Folgendes ausgeführt:
//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>
}
Dies wurde schnell sehr kompliziert zu wissen, was wir welchen Benutzern zeigen sollten. Um dieses Problem zu lösen, haben wir die gesamte Logik dahingehend zentralisiert, wann eine bestimmte Sache angezeigt oder ausgeblendet werden soll. Wir haben diese Klasse aufgerufen UserConfiguration
und sie enthielt (meistens) nur eine Reihe von Funktionen, die Boolesche Werte zurückgeben und angeben, was angezeigt werden soll. Auf diese Weise konnten wir eine Reihe von Spezifikationen und Tests einrichten, die zeigen, was einem Benutzer angezeigt werden soll. Dies UserConfigratuion
wurde dann in eine Basisklasse gestellt, von der alle Seitenmodelle erben mussten. Was wir derzeit haben, ist also ungefähr so:
//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>
}
Dies hat geholfen, vor allem, weil es uns ermöglicht hat, eine Reihe von Tests zu erstellen, was ein Benutzer sehen sollte und was nicht usw. Es ist jedoch keine sehr saubere Lösung, diese zusätzliche Klasse zusammenzustellen und in das Modell aufzunehmen. Es hat auch Auswirkungen auf das Rendern von Teilansichten. Wenn das Modell eine Eigenschaft enthält IEnumerable<Foo> Foos
, die wir in einem Teil rendern möchten, dieser Teil jedoch auch von der Benutzerkonfiguration abhängt, liegt ein Problem vor. Sie können die Foos nicht einfach als Modell an das Partial übergeben, da das Partial dann keinen Zugriff auf das hat UserConfiguration
. Was wäre der beste Weg, um auf diese Informationen zuzugreifen? So wie ich es sehe, stehen im Kontext von asp.net MVC vier Möglichkeiten zur Verfügung:
1) Haben Sie ein neues Modell für den Teil zB
// 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
}
}
Dies ist die wahrscheinlich "reinste" Lösung, die sich am besten an die Prinzipien von MVC hält, aber viele (wohl unnötige) Modelle umfasst, was zu einem Aufblähen des Projekts führt.
2) Stellen Sie die Benutzerkonfiguration über die ViewData bereit. z.B :
// 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
}
}
Ich mag das nicht wirklich, weil es nicht typsicher ist und sich auf magische Zeichenfolgen stützt, um es aus den ViewData zu erhalten.
3) Legen Sie die Benutzerkonfiguration in das ViewBag. Gleiche Probleme wie oben
4) Ändern Sie das Seitenmodell und machen Sie die Benutzerkonfiguration über eine Eigenschaft der Seite selbst verfügbar, wie unter http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view angegeben .aspx /
Ich denke, da es sich bei der Benutzerkonfiguration um kontextbezogene Umgebungsinformationen handelt, ist es sinnvoll, sie über die Klasse wie in Option 4 oben verfügbar zu machen. Gibt es in MVC allgemein anerkannte Best Practices für die Offenlegung dieser Art von Daten? Hat jemand in der Vergangenheit so etwas wie Option 4 ausprobiert und gab es irgendwelche "Gotchas"?
tl; dr: Wie können Kontextinformationen am besten für die Ansichten auf Ihrer Website verfügbar gemacht werden, in MVC im Allgemeinen oder in asp.net MVC im Besonderen?