O motor de visões Razor ASP.NET MVC

Analisamos a sintaxe e suas considerações para o motor de visão Razor em .NET.

Por Eduard Tomás - Tradução CRV


Publicado em: 18/8/11
Valorize este artigo:
Desde sua versão ASP.NET MVC teve o conceito de motor de visão (View Engine). Bom, recapitulemos: em ASP.NET MVC as visões só realizam tarefas de apresentação. Não contêm nenhum tipo de lógica de negócio e não acessam dados. Basicamente se limitam a mostrar dados (no artigo anterior vimos como passar dados dos controladores para as exibições) e a requisitar dados novos ao usuário. Se você vem do mundo de webforms, esqueça o conceito de Web Controls: não existem em ASP.NET MVC. Não temos drag and drop, não configuramos propriedades. As visões são basicamente HTML e o que não é HTML são pequenas porções de código de servidor destinadas a terminar gerando HTML para mostrar informação.

A equipe que desenvolveu ASP.NET MVC teve a feliz ideia de permitir separar a sintaxe de servidor usada do framework de ASP.NET MVC. O resultado? O que chamamos um motor de visão de ASP.NET MVC. Nas versões 1 e 2, o framework vem com um único motor de visão, o chamado motor ASPX, que usa os clássicos arquivos .aspx como visão de ASP.NET MVC. Porém, cuidado! Embora estejamos utilizando arquivos .aspx, não são webforms (os webcontrols não funcionam, não temos viewstate nem o ciclo de vida de webforms e ademais … são visões de MVC, de modo que só devem fazer tarefas de apresentação). A sintaxe que usa o motor ASPX é um pouco… isso que os anglo -saxões chamam verbose, ou seja, deve -se escrever muito para certas tarefas. Assim, imaginem uma página que tivesse que mostrar uma lista de elementos da classe Usuário (a que usamos no capítulo anterior). O código, usando o motor de visão ASPX fica assim:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MvcHelloWorld.Controllers.Usuario>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
DemoAspx
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>DemoAspx</h2>
<table>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: item.Nome %>
</td>
<td>
<%: item.Twitter %>
</td>
<td>
<%: String.Format("{0:g}", item.Registro) %>
</td>
</tr>
<% } %>
</table>
</asp:Content>

Observem a quantidade de vezes que se deve usar o tag <% e seu semelhante %> para indicar onde começa e termina o código de servidor.

Rapidamente começaram a surgir motores de visão alternativos, realizados pela comunidade, com a intenção de ter sintaxes mais claras para nossas exibições. Alguns exemplos são Nhaml y Spark.

Finalmente a versão 3 de ASP.NET MVC veio acompanhada de um novo motor de visão, chamado Razor. Isso sim, o motor ASPX pode seguir sendo usado em ASP.NET MVC3, mas honestamente não há nenhuma razão para fazê-lo (salvo em casos de migrações, obviamente): Razor é mais claro, simples e intuitivo.

Sintaxe de Razor

O que mais surpreende em Razor é que, diferentemente do motor ASPX onde temos o tag que inicia o código de servidor e aquele que o termina, só há tag para iniciar código de servidor. O motor Razor é suficientemente inteligente para saber quando termina o código de servidor, sem necessidade de que o explicitemos. Vejamos a mesma exibição de antes, mas agora usando Razor:

@model IEnumerable<MvcHelloWorld.Controllers.Usuario>
@{
ViewBag.Title = "DemoRazor";
}
<h2>DemoRazor</h2>
@foreach (var item in Model) {
<tr>
<td>
@item.Nome
</td>
<td>
@item.Twitter
</td>
<td>
@String.Format("{0:g}", item.Registro)
</td>
</tr>
}
</table>

As diferenças saltam à vista, não? Em Razor o símbolo da arroba (@) marca o inicio de código de servidor. E como comentava antes, não há símbolo para indicar que acaba o código de servidor: o motor Razor deduz quando termina com base no contexto.

Observem que para mostrar uma variável de servidor (item.Nome p.ex.) simplesmente a precedemos de uma @. Observem também que a chave de fechamento do foreach não deve ser precedida de nenhuma arroba. Razor já sabe que essa chave é de servidor e fecha o foreach aberto.

O uso da @ funciona de duas maneiras básicas:

  1. @expressão: Renderiza a expressão no navegador. Assim @item.Nome mostra o valor de item.Nome. Ou seja, @expressão equivale a <%: expressão %>
  2. @{ código }: Permite executar um código que não gera saída HTML. Ou seja, @{código} equivale a <% Código %>

Considerações da sintaxe

Expressões complexas
Como vimos o motor Razor interpreta quando começa e quando termina o código de servidor. Mas nem sempre o consegue adequadamente. P.ex, o seguinte código Razor:

@{ int a = 10; int b = 3; }

O valor de 10 - 3 é: @a-b

Gera o seguinte HTML:

O valor de 10 - 3 é: 10-b

Ou seja, Razor interpretou que o código de servidor terminava ao encontrar o símbolo de diminuição. Neste caso, essa suposição é totalmente errônea, mas por sorte podemos usar os parênteses para que haja apenas uma expressão depois da arroba:

O valor de 10 - 3 é: @(a-b)

Com esse código a visão mostrará o valor correto (7). Lembrem a chave: o motor Razor espera uma e só uma expressão depois da @. Por isso, devemos usar os parênteses.

"Romper" o código de servidor
Às vezes, a problemática é justamente contrária à que vimos com as expressões complexas: às vezes há código que Razor interpreta como sendo de servidor, quando na verdade parte desse código é HTML que deve ser enviado ao cliente. Vejamos um exemplo:

@for (int i = 0; i < 10; i++)
{
O valor de i é: @i <br />
}

A priori poderíamos esperar que este código gerasse 10 linhas de código HTML. Porém, o resultado é um erro de compilação. A razão é que Razor interpreta que a linha "O valor de i é: @i" é código de servidor. Para "romper" este código de servidor e fazer com que Razor "saiba" que realmente isto é código que deve ser enviado tal qual ao cliente, temos duas opções:

1. Intercalar uma etiqueta HTML. Ao intercalar uma etiqueta HTML Razor "se dá conta" de que ali começa um código de cliente:

@for (int i = 0; i < 10; i++)
{
<span>O valor de i é:</span> @i <br />
}

2. Usar a construção @: que indica explicitamente a Razor que aquilo que segue é código de cliente:

@for (int i = 0; i < 10; i++)
{
@:O valor de i é: @i <br />
}

A diferença é que no primeiro caso as etiquetas são enviadas ao navegador, enquanto que no segundo caso, não.

Considerações em correios eletrônicos

As pessoas que desenvolveram o motor Razor fizeram uma exceção para os correios eletrônicos. Ou seja, Razor é de novo suficientemente inteligente para saber que uma expressão é um correio eletrônico. Portanto, o código seguinte não dá erro e envia o HTML esperado para o cliente:

Envie-me um mail: a usuario@servidor.com

Neste caso Razor interpreta que se trata de um correio eletrônico, de modo que não trata a @ como inicio de código de servidor. Este comportamento às vezes tampouco se deseja. P.ex, imaginem o seguinte:

<div id="div_@Model.Index">Div usado</div>

Estou assumindo que o ViewModel que recebe a visão tem uma propriedade chamada Index. Suponhamos que dita propriedade (Model.Index) vale 10. A verdade é que se pensaria que isso geraria o código HTML:

<div id="div_10">Div usado</div>

Porém, o resultado é bem diferente. O código HTML gerado é:

<div id="div_@Model.Index">Div usado</div>

Ou seja, Razor não interpretou a @ como início de código de servidor, e isso porque aplicou a exceção de correio eletrônico. A solução passa por usar os parênteses:

<div id="div_@(Model.Index)">Div usado</div>

Agora Razor sabe que Model.Index é código de servidor e o avaliará, gerando o HTML que estávamos esperando.

Às vezes, Razor falha, inclusive exageradamente. Dado o seguinte código:

@for (int i = 0; i <= 1; i++)
{
<div id="div_@i">Div @i</div>
}

Com base no que vimos poderíamos esperar que fosse gerado o seguinte HTML:

<div id="div_@i">Div 0</div>
<div id="div_@i">Div 1</div>

Pois não! Este código faz com que o motor de Razor dê um erro (The for block is missing a closing "}" character. Make sure you have a matching "}" character for all the "{" characters within this block, and that none of the "}" characters are being interpreted as markup).

Obviamente, a solução para gerar o HTML que queremos passa por usar os parênteses igual que antes:

@for (int i = 0; i <= 1; i++)
{
<div id="div_@(i)">Div @i</div>
}

Gera o HTML esperado:

<div id="div_0">Div 0</div>
<div id="div_1">Div 1</div>
Escapar da arroba
Algumas vezes é necessário indicar ao Razor que uma arroba é isso… uma simples arroba e que não faça nada específico. Que não assuma nada, que não pense nada, que simplesmente envie uma @ ao cliente. Um exemplo? O seguinte código:

<style>
@@media screen
{
body { font-size: 13px;}
}
</style>

Se não usássemos a dupla arroba (@@), Razor geraria um erro, já que @media o interpreta como "enviar o conteúdo da variável media ao cliente". Neste caso ao usar @@ Razor simplesmente sabe que deve enviar uma @ para o cliente e o que o navegador recebe é:

<style>
@media screen
{
body { font-size: 13px;}
}
</style>

Conclusões

Vimos a sintaxe básica do motor de visões Razor, e as principais considerações que devemos ter presentes. Não vimos as capacidades adicionais de tal motor de visão tais como layouts, templates e regiões que iremos vendo em capítulos posteriores.

Para finalizar, uma pequena coisa: Ambos motores de visão (ASPX e Razor) podem ser usados em MVC3 de forma simultânea. O motor de ASP.NET MVC tentará encontrar primeiro uma visão .aspx e se não a encontrar buscará uma visão Razor (.cshtml, embora também possa ser .vbhtml se usarmos Visual Basic.NET em lugar de C#). Ainda que, obviamente, este comportamento possa ser modificado.
Um abraço a todos!






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

Home | Sobre nós | Copyright | Anuncie | Entrar em contato