Rendering de vistas parciales en Razor y MVC3

Publicado 25/2/2011 8:53 por Eduard Tomàs i Avellana

Buenas! Una de las dudas que he visto que se van repitiendo por ahí tiene que ver con como renderizar vistas parciales en MVC3 usando Razor.

En MVC2 y anteriores (o en MVC3 usando el ViewEngine de WebForms) la forma de renderizar una vista parcial era sencilla:

<% Html.RenderPartial("VistaParcial", modelo); %>

Mucha gente traduce eso a Razor y usa lo siguiente para renderizar una vista parcial:

@Html.RenderPartial("VistaParcial")

Y se obtiene un error, quizá un poco críptico, que dice lo siguiente: CS1502: The best overloaded method match for 'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)' has some invalid arguments

El error no está en que Html.RenderPartial no pueda usarse con Razor, el error está en la sintaxis que estamos usando. Cuando en Razor usamos la @ para indicar el inicio de código de servidor, la expresión que viene a continuación debe devolver un valor, que será incluído en la respuesta a enviar al navegador. La excepción a esa norma es cuando lo que sigue a la @ es una palabra clave reservada de Razor (como @model) o una palabra clave reservada del lenguaje que estemos usando (como @foreach). Esos casos especiales Razor los sabe tratar y actúa en consecuencia. Pero en el resto de casos siempre, siempre, siempre la expresión debe devolver un valor.

Hablando en términos del engine de WebForms, el código Razor:

@Html.RenderPartial("VistaParcial", modelo)

Se corresponde a:

<%: Html.RenderPartial("VistaParcial",modelo) %>

Que es erróneo (y da el error CS1502: The best overloaded method match for 'System.Web.HttpUtility.HtmlEncode(string)' has some invalid arguments).

Entonces… como usar Html.RenderPartial en Razor? Fácil: usando llaves para indicarle al motor de Razor que eso es un código que debe ejecutar, en lugar de un valor que debe incrustar en la respuesta:

@{ Html.RenderPartial("VistaParcial"); }

Así pues: Html.RenderPartial puede usarse en Razor sin ningún problema… como el resto de Helpers que conozcáis. Si el método lo usábais con <% … %> en Razor es @{ … }, mientras que si usábais <%: … %> en Razor es simplemente @…

Otras maneras de incrustar vistas parciales

De todas formas hay un par de métodos más para incrustar vistas parciales.

El primer método es Html.Partial() un método de extensión adicional. Para llamarlo se usan los mismos parámetros que Html.RenderPartial. La diferencia es que Html.Partial devuelve una IHtmlString con los contenidos de la vista renderizada. Por lo tanto, para incrustar una vista usando Html.Partial() usamos:

// Razor
@Html.Partial("VistaParcial")
// Webforms viewengine
<%: Html.Partial("VistaParcial") %>

El segundo método es propio de Razor, ya que está definido dentro del framework que se conoce como “WebPages” y es usar el método RenderPage, definido en la clase WebPageBase de la cual heredan las vistas Razor.

Dicho método acepta dos parámetros:

  1. La localización de la vista. Ojo! No el nombre, sinó su localización (incluyendo directorios)
  2. Parámetros a pasar a la vista (params object[]).

P.ej. para renderizar la vista parcial usaríamos:

@RenderPage("~/Views/Home/VistaParcial.cshtml")

Fijaos en que se debe usar el nombre del archivo de la vista a incluir (incluyendo extensión .cshtml).

Si se pasan parámetros a la vista parcial, estos no están disponibles usando la propiedad Model en la vista, sinó que debe usarse la propiedad PageData. P.ej. podríamos pasar una cadena y un entero a la vista:

@RenderPage("~/Views/Home/VistaParcial.cshtml", "Parametro 1", 10)

Y mostrarlos desde la vista con el uso de PageData:

@foreach (var item in PageData)
{
<div>@item.Value</div>
}

Mi opinión sobre el método RenderPage (en MVC): Sobra totalmente, y espero que nunca, nunca, nunca lo uséis. Porque? Pues porque RenderPage rompe la encapsulación del framework (en lugar de especificar un nombre de vista debéis especificar un fichero). Es evidente que existe para dar soporte a WebPages pero WebPages y MVC se parecen sólo porque usan Razor como sintaxis, pero en concepción son dos cosas totalmente distintas… Aunque por razones (supongo que técnicas) Razor depende de WebPages y esa dependencia se arrastra a MVC3, cosa que personalmente no me gusta demasiado. Pero es lo hay… ;-)

Conclusiones

  1. Html.RenderPartial funciona correctamente en Razor, al igual que el resto de métodos de siempre. Sólo debemos tener cuidado en usar la sintaxis correcta.
  2. Html.Partial es un método adicional para renderizar vistas parciales. La diferencia con Html.RenderPartial() es que este último escribe en la response directamente el contenido de la vista, mientras que Partial() lo devuelve dentro de una cadena. No tengo claras las implicaciones de rendimiento que puede tener empezar a crear mutltiud de cadenas que serán eliminadas por el GC casi de inmediato.
  3. RenderPage es el método de WebPages para renderizar vistas parciales. Desde el punto de vista de MVC es un método que sobra totalmente y que rompe la encapsulación del framework.

Espero que os sea útil!

Un saludo!

Archivado en:
Comparte este post: