Quando si ha a che fare con siti che prevedono un gran numero di View capita spesso di trovarsi a inserire ripetutamente alcune variabili nell'oggetto ViewBag di ciascuna di esse. Alcuni esempi tra i più ricorrenti, per lo meno nei miei progetti, sono i classici IsAdmin, IsAuthenticated, AvatarURL e così via. In questo tipo di situazioni, onde evitare di scrivere ripetutamente lo stesso codice, è consigliabile adottare un metodo che consenta di inserire queste variabili nel ViewBag di tutte le viste in modo centralizzato. Gli approcci che vanno per la maggiore per ottenere questo risultato sono i seguenti:
1. Utilizzare una Base Class.
1 2 3 4 5 6 7 8 |
public class BaseController : Controller { protected override ViewResult View(IView view, object model) { this.ViewBag.MyProperty = "value"; return base.View(view, model); } } |
PRO: Semplice da implementare, efficace, centralizzato (fin troppo).
CONTRO: Costringe a derivare tutti i controller dalla base class, il che può risultare sconveniente se si ha a che fare con un gran numero di controller già esistenti e/o basati su classi base non modificabili.
2. Utilizzare un Module.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class ViewBagPropertyModule: Module { protected override void AttachToComponentRegistration(IComponentRegistry cr, IComponentRegistration reg) { Type limitType = reg.Activator.LimitType; if (typeof(Controller).IsAssignableFrom(limitType)) { registration.Activated += (s, e) => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.MyProperty= "value"; }; } } } |
PRO: Nessuno in particolare.
CONTRO: Nessuno in particolare (a parte una scarsa intuitività del metodo).
3. Impostare la proprietà in fase di RegisterController
1 2 3 4 5 |
builder.RegisterControllers(asm) .OnActivated(e => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.MyProperty = "value"; }); |
PRO: Ideale per un design pattern basato su IoC.
CONTRO: Non ha molto senso in tutti gli altri casi.
4. Utilizzare un ActionFilter e registrarlo in fase di Global.asax / Application_Start.
1 2 3 4 5 6 7 |
public class MyPropertyActionFilter : ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.Controller.ViewBag.MyProperty = "value"; } } |
1 2 3 4 5 |
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalFilters.Filters.Add(new MyPropertyActionFilter(), 0); } |
PRO: E' il metodo meno invasivo (e più versatile) tra quelli proposti.
CONTRO: Nessuno in particolare.
Come sempre, la soluzione preferibile varia a seconda delle caratteristiche del progetto e delle necessità dello sviluppatore: ciò detto, la mia preferita è senz'altro la quarta per i motivi espressi.
E la vostra?