Razor – nowy silnik renderujący w ASP.NET MVC 3.0
Autor: Piotr Zieliński
Opublikowano: 2011-03-30
Wprowadzenie
Wersja 3.0 dostarcza nowy silnik renderujący, który znacząco upraszcza projektowanie widoków. W poprzednich wersjach do dyspozycji był wyłącznie aspx o dość niewygodnej składni. Razor posiada prostszą składnię, która wymaga po prostu mniejszej ilości kodu do uzyskania takich samych efektów co aspx. ASP.NET MVC daje pełną swobodę i można wykorzystywać w swoich projektach zarówno ASPX, jak i Razor. Istnieje również kilka innych silników, takich jak SPARK czy NHaml.
Podstawowa składnia Razor
Wyświetlanie zmiennych
Rozważmy wyświetlenie tekstu z modelu oraz daty za pomocą ASPX:
<h1>
Witaj <%=ViewBag.Name %>! Aktualna data to <%=DateTime.Now %>
</h1>
W ASPX należy zamykać tagi znakami %>. Jest to dość kłopotliwe, zwłaszcza gdy trzeba wpisywać znak procenta (%), który znajduje się w mało wygodnej części klawiatury.
W przypadku Razor kod uprości się do:
<h1>
Witaj @ViewBag.Name ! Aktualna data to @DateTime.Now
</h1>
W Razor wystarczy przed zmienną umieścić znak @ – nie trzeba zamykać, tak jak w przypadku ASPX tagu. Jak widać, za pomocą tylko jednego znaku byliśmy w stanie wyświetlić zawartość zmiennej.
Pętle z zagnieżdżonym kodem HTML
W przypadku pętli przewaga Razor jest jeszcze bardziej widoczna (w ASPX niewygodne jest zamykanie nawiasów):
<%foreach(var item in Model){ %>
<p><%=item %></p>
<%} %>
W Razor kod bardziej przypomina czysty C#, ponieważ nie trzeba definiować tagów za pomocą <%>:
@foreach (var item in Model)
{
<p>@item</p>
}
Instrukcje sterujące IF
Przewagę Razor widać również na przykładzie instrukcji if (w przypadku ASPX prosty warunek wyglądał dość skomplikowanie):
<%if (Model.Length == 0)
{ %>
<p>Brak towaru</p>
<%}
else
{ %>
<p>Towar dostepny</p>
<%} %>
W Razor wygląda to znacznie prościej:
@if (Model.Length == 0)
{
<p>Brak towaru</p>
}
else
{
<p>Towar dostepny</p>
}
Kod pomiędzy klamrami musi być umieszczony w tagu HTML – w naszym przykładzie jest to <p>. Nie możemy bezpośrednio umieszczać tekstu pomiędzy klamrami. W przypadku gdy nie chcemy użyć żadnego formatowania HTML (takiego jak np. <p>), możemy wykorzystać element text:
@if(Model.Length!=0)
{
<text>
Jakis tekst
</text>
}
Text stanowi specjalny element i nie zostanie on wygenerowany w docelowej stronie HTML (strona będzie zawierała wyłącznie zawartość elementu <text></text>).
Sekcje kodu
Jeśli potrzebujemy wykonać kod składający się z kilku linii, należy go umieścić w sekcji @{ }:
@{
string text="Hello";
text+=" World";
}
@text
Warto jednak pamiętać o podstawowej zasadzie MVC, która mówi, że widok powinien wyświetlać dane, a nie je generować. Powyższa sekcja jest analogiczna do <% %>, znanej z ASPX.
Wyświetlanie konkatenacji
Razor dysponuje również odpowiednikiem sekcji<%= %> (ASPX). Jeśli chcemy wyświetlić złączenie zmiennych, korzystamy z @( ):
@("Witaj " + ViewBag.Name)
Zawartość ze znakiem @
Jak już zapewne zostało zauważone, Razor opiera się na znaku @. A jeśli zechcemy, aby znak @ został potraktowany jako treść? W większości przypadków nic nie musimy robić, ponieważ Razor sam potrafi zdecydować, czy @ w danym kontekście służy jako znak specjalny, czy jako treść. Wyświetlając adres e-mail (np. contact@mail.com), parser analizuje kolejne słowa i stwierdzi, że w tym kontekście na pewno nie chodziło o zmienną tylko o zwykły tekst. Czasami jednak sytuacja jest nierozstrzygalna dla parsera i wtedy należy skorzystać z podwójnego znaku @@ – wówczas jawnie zostanie określone, że chodzi o tekst.
Szablony stron – master pages
Obsługa szablonów jest również prostsza i nie wymaga pisania długiej dyrektywy Page. Szablon definiujemy w pliku cshtml. Przykład (layout.cshtml):
<html>
<head>
<title>Tytul</title>
</head>
<body>
<div>Częśc wspólna</div>
<div>@RenderBody()</div>
</body>
</html>
W szablonie definiujemy część, która będzie powtarzana na różnych stronach, oraz wywołujemy funkcje RenderBody w miejscu, gdzie ma zostać umieszczona część specyficzna dla danej strony. Następnie w konkretnej stronie podłączamy szablon za pomocą właściwości Layout:
@{
Layout="Layout.cshtml";
}
<p>Jakis Tekst</p>
Wystarczy ustawić tylko pojedynczą właściwość – nie trzeba definiować długiej dyrektywy jak to miało miejsce w aspx. Następnie w pliku umieszczamy treść, która zostanie wstrzyknięta w miejsce wywołania funkcji RenderBody.
Istnieje również możliwość zdefiniowana sekcji w szablonie. Możemy w końcu szablon podzielić na części takie jak stopka, nagłówek, tytuł itp. W takiej sytuacji należy wywołać funkcję RenderSection, przekazując jako parametry nazwę sekcji oraz wartość określającą, czy jest ona wymagana:
<html>
<head>
<title>@RenderSection("title", true)</title>
</head>
<body>
<div>Częśc wspólna</div>
<div>@RenderBody()</div>
</body>
</html>
Następnie w szablonie wstrzykujemy tekst w odpowiednią sekcję za pomocą konstrukcji @section:
@{
Layout="Layout.cshtml";
}
<p>Jakis Tekst</p>
@section title
{
Tytul strony
}
Własny helper
Nierzadko generowanie widoku jest procesem skomplikowanym ze względu na bogate formatowanie HTML. Własne helpery umożliwiają wydzielenie powtarzających się fragmentów strony. Załóżmy, że często na stronie wyświetlamy kolekcję danych w formie tabelarycznej. Powtarzanie tej samej konstrukcji za każdym razem jest z pewnością mało eleganckim rozwiązaniem. Helper w działaniu przypomina procedurę – przyjmuje parametry i wykonuje jakąś czynność (w tym przypadku polegającą na wygenerowaniu treści). Przykład:
@helper FirstHelper(string text)
{
<p>@text</p>
}
Następnie w dowolnym miejscu strony możemy go wywołać:
@FirstHelper("jakis tekst");
W praktyce oczywiście nie ma sensu pisanie tak prostego helpera. Przeważnie będzie to konstrukcja z pętlą i licznymi elementami HTML.
W Razor można również przekazywać parametry do wszelkich w funkcji w nieco inny sposób (inline):
@Funkcja(parametr:"wartosc",parametr2:"wartosc2");
Zakończenie
Razor optymalizuje proces tworzenia widoków. Jedną z jego cech charakterystycznych jest prostota i przejrzystość. Wystarczy znajomość C#, aby swobodnie pisać elastyczne szablony. Visual Studio oferuje również wsparcie ze strony Intellisense, co bardzo ułatwia pracę. Warto podkreślić, że Razor i ASPX mogą być stosowane zamiennie dla różnych widoków tym samym projekcie. Oznacza to, że projekt rozpoczęty w poprzednich wersjach (w ASPX) można rozszerzać, wykorzystując silnik Razor.