Usare un action filter per popolare dati del model in ASP.NET MVC

di Marco De Sanctis, in ASP.NET 4.0,

Nel precedente script #1013 abbiamo visto come, in un'applicazione ASP.NET MVC, le partial view rappresentino il modo più efficace per realizzare template riutilizzabili, così che dati dello stesso tipo possano essere visualizzati in maniera consistente in diverse pagine. Quando questi dati provengono da una fonte esterna, però, siamo comunque costretti a replicare la logica per il loro caricamento.

Pensiamo ad una tag cloud in un blog engine, ad esempio; anche se realizziamo una partial view TagCloud.ascx, dovremo comunque preoccuparci di popolare il relativo model in ogni action che voglia visualizzarla:

public ActionResult Index()
{
  using (var ctx = new BlogEntities())
  {
    this.ViewData["tagCloud"] = 
      from p in Posts
      from c in p.Categories
      ...
  }
    
  // .. altro codice qui ..
}

public ActionResult ShowPost()
{
  using (var ctx = new BlogEntities())
  {
    this.ViewData["tagCloud"] = 
      from p in Posts
      from c in p.Categories
      ...
  }
    
  // .. altro codice qui ..
}

In realtà possiamo avvalerci di un metodo più elegante, che consiste nell'integrare in un action filter tale logica. Un action filter, in ASP.NET MVC, è un oggetto il cui funzionamento ricorda un po' quello di un HttpModule, e ci consente di iniettare codice personalizzato durante l'esecuzione di una action. Per realizzarlo è sufficiente creare una classe che erediti da ActionFilterAttribute.

public class LoadTagCloudAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    base.OnActionExecuting(filterContext);

    List<TagCloudItem> items = 
      filterContext.HttpContext.Cache["tagCloud.Items"] as List<TagCloudItem>;

    if (items == null)
    {
      using (var ctx = new BlogEntities())
      {
        items = from p in Posts
                from c in p.Categories
                ...
        filterContext.HttpContext.Cache.Insert("tagCloud.Items", items
          null,
          DateTime.MaxValue, TimeSpan.FromMinutes(30));
      } 
    }
    
    filterContext.Controller.ViewData["tagCloud"] = items;
  }
}

ActionFilterAttribute espone quattro entry point a cui è possibile agganciarsi per iniettare il proprio codice personalizzato nella pipeline di ASP.NET MVC, corrispondenti a diverse fasi dell'esecuzione della richiesta, ossia:

  • OnActionExecuting e OnActionExecuted: vengono invocati rispettivamente prima e dopo che la action del controller venga eseguita;
  • OnResultExecuting e OnResultExecuted: simili ai due precedenti, ma relativi all'esecuzione della risposta ritornata dalla action (quindi, ad esempio, nel caso di una ViewResult, prima e dopo che sia stato effettuato il rendering della View).

La classe LoadTagCloudAttribute, nel nostro caso, effettua l'override del metodo OnActionExecuting per popolare il dictionary ViewData con le informazioni relative alla TagCloud, sfruttando anche la cache di ASP.NET per evitare chiamate ridondanti.

Affinché essa venga eseguita in corrispondenza di una action, è sufficiente decorare quest'ultima con l'attributo che abbiamo creato.

[LoadTagCloud]
public ActionResult Index()
{   
  // .. qui solo il codice specifico della action ..
}

Eventualmente è anche possibile specificarla a livello di controller, così che tale impostazione valga per tutte le action che gli appartengono:

[LoadTagCloud]
public class HomeController : Controller
{
  // .. codice qui ..
}

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi