ASP.NET MVC3: Razor Templates

Muy buenas!

En este post quiero comentaros una característica de Razor que yo considero que es una auténtica pasada: los templates.

Básicamente el meollo de todo está en la posibilidad de guardar el resultado de un parseo de Razor en un Func<T, HelperResult> siendo T el tipo del modelo que renderiza el template.

Veámoslo con código:

@{
Func<string, HelperResult> h =
@<h2>Esto es un template al que se le han pasado los datos: @item</h2>
;
}
<p>
Renderizamos el template: @h("datos")
</p>

Fijaos como nos guardamos en una Func<string, HelperResult> el resultado de renderizar un template razor (en este caso el template <h2>…</h2>). Fijaos en tres detalles:

  1. Dado que la variable h está declarada como Func<string, HelperResult> el tipo del modelo en este template es “string”
  2. Para acceder al modelo que se pasa al template se usa @item
  3. Al final del template Razor ponemos un ; (eso es una declaración C# y como tal debe terminar en punto y coma).

Luego más adelante renderizamos el template, con el código: @h("datos")

Eh!! Eso no es lo mismo que @helper?

Si conoces @helper te puede parecer que esto no es muy novedoso. Con @helper podemos crear helpers inline de la siguiente manera:

@helper h2(string s) {<h2>Esto es un helper: @s</h2>}

Y lo podíamos invocar con:

@h2("ufo")

Por lo que parece que viene a ser lo mismo. Y es que, en el fondo, ambas construcciones devuelven un HelperResult.

Nota: Si quieres más información sobre @helper, léete el post que hizo el maestro hace algún tiempecillo: http://www.variablenotfound.com/2010/11/y-mas-sobre-helpers-en-razor.html

Lo interesante no es que ambas construccione se parezcan, lo que quiero recalcar es que…

… Los templates son Func<T, HelperResult>!

Lo pongo así en negrita porque eso es importante, y a la vez me sirve de título. Si los templates Razor son Func<T, HelperResult>… cualquier método que reciba un Fun<T, HelperResult> puede recibir un template Razor

… Incluídos los helpers!

@helper Repeater(int count,Func<dynamic, HelperResult> template, string data) {
<ul>
@for (int idx=0; idx<count; idx++)
{
<li>@template(new { Text = data, Index = idx })</li>
}
</ul>
}

@Repeater(10, @<span>@item.Text (item: #@item.Index)</span>, "Ufo")

En este código:

  1. Declaramos un helper, llamado Repeater que acepta tres parámetros:
    1. Un entero
    2. Un Func<dynamic, HelperResult> que por lo tanto podrá ser un template Razor
    3. Una cadena
  2. El helper se limita a crear una lista y luego:
    1. Crea tantos <li> como indica el paràmetro count y en cada id
      1. Evalúa el segundo parámetro (que es el Func) y le pasa como parámetro un objeto anonimo con dos propiedades (Text e Index), donde Text es el tercer parámetro que recibe (y index el valor de la iteración actual).
  3. Cuando invocamos al helper, le pasamos como primer parámetro el número de repeticiones, como segundo parámetro un template de Razor. Fijaos que dentro de dicho template:
    1. Accedemos a las propiedades @item.Text y @item.Index. Eso podemos hacerlo porque hemos declarado el tipo del modelo de dicho template como dynamic y por eso nos compila (y nos funciona porque el helper cuando invoca el template crea esas propiedades en el objeto anónimo).

El código HTML generado por dicha llamada al helper Repeater es:

<ul>
<li> <span>Ufo (item: #0)</span></li>
<li> <span>Ufo (item: #1)</span></li>
<li> <span>Ufo (item: #2)</span></li>
<li> <span>Ufo (item: #3)</span></li>
<li> <span>Ufo (item: #4)</span></li>
<li> <span>Ufo (item: #5)</span></li>
<li> <span>Ufo (item: #6)</span></li>
<li> <span>Ufo (item: #7)</span></li>
<li> <span>Ufo (item: #8)</span></li>
<li> <span>Ufo (item: #9)</span></li>
</ul>

Espero que el post os haya resultado interesante!!! 😉

Saludos!

6 comentarios sobre “ASP.NET MVC3: Razor Templates”

  1. Buenas, Eduard!

    Esta era una de las cosas que más me descolocaron de Razor, hasta que conseguí entenderla… es que parece pura magia eso de meter una arroba en mitad del código y que todo funcione.

    Gran explicación, amigo, y gracias por la referencia 🙂

    Un saludo!

  2. Buenas!

    La verdad es que a mi también me costó un poco de digerir… és aquello que lo ves y te preguntas «que está haciendo eso exactamente?», jejejeee…

    Luego una vez «entendido», a mi me parece una pasada, la verdad! Es otro guiño más a la programación funcional! 😀
    Y les da una potencia tremebunda a los helpers! 😉

    Saludos!!!

  3. Hola Eduard,

    Un post como un melón maduro, muy bueno pero difícil de tragar con tanto jugo en cada bocado 😉

    Pero me surge una duda, imagina que quiero reutilizar el helper Repeat en varias de mis vistas, ¿es posible definir el helper en un archivo aparte e importarlo en todas las vistas que quieran usarlo, tengo que definirlo en cada página o en la master y estará accesible por todas las vistas que incluyan esa master,…?

    Un saludo.

  4. @Bernardo
    Muchas gracias por tu comentario!

    xD La verdad es que parece que nos hayamos sincronizado… en la entrada que sigue a esta (http://geeks.ms/blogs/etomas/archive/2011/01/26/asp-net-mvc3-un-helper-repeater.aspx) comento exactamente lo que tu pides: como hacer un helper reutilizable entre varias vistas.
    En este caso adoptando la técnica de crear una clase estática que exponga un método estático que devuelva el HTML (y usando templates por supuesto).

    Colocar un helper (usando @helper) en la master page, no sirve de nada ya que NO estará disponible en todas las vistas, y tampoco te va a servir colocarlo en _ViewStart.cshtml.

    Un saludo y de nuevo muchas gracias por tu comentario!

  5. Todos tus artículos me parecen muy buenos. Solo echo una cosa en falta.

    —-> Poder imprimirlos correctamente… 🙁

    Me gustaría poder leerlos en el bus, en el tren o, simplemente, archivarlos impresos. Pero, aunque es posible, no quedan bien del todo.

    Si puedes hacer algo al respecto. Fenomenal.

    Gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *