Scusate il lungo post. C'è una domanda, limitati a sopportare me.
Un piccolo contesto
Abbiamo un sito che è necessario adattare considerevolmente in base a una varietà di impostazioni utente, al gruppo a cui appartiene l'utente, da dove provengono e ad altre cose. Abbiamo usato per includere i bit rilevanti sul modello per la pagina, quindi se la pagina avesse una tabella che mostra se l'utente aveva più di una certa età, sul modello faremo qualcosa del tipo:
//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>
}
Questo è diventato rapidamente molto complicato sapere cosa dovremmo mostrare a quali utenti. Per cercare di risolvere questo problema, abbiamo centralizzato tutta la logica su quando una determinata cosa dovrebbe essere mostrata o nascosta. Abbiamo chiamato questa classe UserConfiguration
e questa (per lo più) conteneva solo una serie di funzioni che restituivano booleani indicando cosa dovrebbe essere mostrato. Questo ci ha permesso di impostare una serie di specifiche e test su ciò che un utente dovrebbe mostrare. Questo UserConfigratuion
è stato quindi messo su una classe base, da cui tutti i modelli di pagina erano obbligati ad ereditare, quindi quello che abbiamo attualmente è qualcosa del genere:
//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>
}
Questo ha aiutato, soprattutto perché ci ha permesso di creare una serie di test su ciò che un utente dovrebbe e non dovrebbe vedere ecc. Tuttavia, non è una soluzione molto pulita, dovendo mettere insieme questa classe aggiuntiva e includerla il modello. Ha anche ramificazioni per il rendering di viste parziali. Se il modello ha una proprietà IEnumerable<Foo> Foos
su di esso, che vogliamo rendere in modo parziale, ma quella parte anche si basa sulla configurazione dell'utente, abbiamo un problema. Non puoi semplicemente passare il foos al Partial come modello, perché il partial non ha accesso a UserConfiguration
. Quindi quale sarebbe il modo migliore per accedere a queste informazioni. Per come la vedo io, nel contesto di asp.net MVC ci sono 4 modi disponibili:
1) Avere un nuovo modello per il parziale ad es.
// 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
}
}
Questa è probabilmente la soluzione "più pura", che aderisce meglio ai principi di MVC, ma coinvolge un sacco di modelli (probabilmente inutili), causando un gonfiamento del progetto.
2) Esporre la UserConfiguration tramite ViewData. ad esempio:
// 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
}
}
Non mi piace molto perché non è sicuro e si basa su stringhe magiche per ottenerlo dal ViewData.
3) Metti la UserConfiguration nel ViewBag. Stessi problemi di cui sopra veramente
4) Modificare il modello di pagina ed esporre UserConfiguration tramite una proprietà della pagina stessa, come per link
Ritengo che, dal momento che UserConfiguration è un'informazione contestualizzata ambientale, abbia senso esporla tramite la classe come nell'opzione 4 di cui sopra. È generalmente accettata la best practice in MVC per esporre questo tipo di dati? Qualcuno ha provato qualcosa come l'opzione 4 in passato e ci sono stati 'gotcha'
tl; dr: Qual è il modo migliore di esporre le informazioni contestuali alle viste sul tuo sito, in MVC in generale o asp.net MVC in particolare?