Главная страница   /   17.3. Изучение движка представления Spark (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

17.3. Изучение движка представления Spark

По умолчанию в ASP.NET MVC приложении для определения места размещения представлений и их отображения используется движок представления Razor. Но для разработки и отображения наших представлений мы не обязаны использовать Web Forms. Одной из возможностей расширения ASP.NET MVC является возможность выгружать используемый по умолчанию движок представления из оперативной памяти для различных реализаций. Посредством другого движка представления мы получаем другой опыт определения и разработки представлений.

К популярным альтернативным движкам представления, поддерживаемым в ASP.NET MVC посредством различных достижений открытого кода, относятся NHaml и Spark:

Но зачем нам может понадобиться изучать другие движки представления? Одной из проблем движка представления Razor является тот факт, что вам не предоставляется достаточно возможностей для кодирования на стороне сервера, за исключением сложных языков программирования таких, как C# и VB.NET. Несмотря на то, что эти языки достаточно мощные, имейте в виду, что кодом, в который вставлена разметка, сложно управлять. Для создания простого цикла HTML требуется цикл foreach и фигурные скобки вперемешку с нашими HTML тегами. В случае более сложной логики представления в данной ситуации совершенно невозможно понять, что происходит.

Движок представления Web Forms, вышедший в свет вместе с ASP.NET MVC 1.0, в большинстве случаев все еще является самым предпочтительным вариантом, но он не уместен для MVC-стилизованных приложений, в которых для наших представлений почти гарантированно необходим код. Несмотря на то, что этот код сконцентрирован строго вокруг представления, он все еще неизбежен. В движке представления Razor значительно улучшен синтаксис по сравнению с первичным движком представления Web Forms, но в нем до сих пор всего лишь совершенствуется существующий синтаксис, а не предлагаются альтернативные варианты.

Эти альтернативные движки представления созданы скорее как движки представления, а не наследия или усовершенствования эпохи Web Forms. Каждый из этих движков оптимизирован для создания MVC представлений, а многие из них являются переносными версиями других созданных движков представления для других MVC фреймворков. Например, NHaml – переносная версия популярного (и весьма выразительного) движка представления Haml (http://haml-lang.com/). Несмотря на то, что встроенный движок представления хорошо работает в рамках большинства ASP.NET MVC приложений, мы все-таки рассмотрим здесь одну из альтернатив этому движку.

Spark – это движок представления, созданный для ASP.NET MVC и MonoRail (www.castleproject.org/monorail/). Spark предоставляет уникальную смесь строчного кода на C# с HTML, замаскированную как XML элементы и атрибуты. В некоторых движках представления присутствуют такие недостатки, как отсутствие IntelliSense и несколько меньшая интеграция с Visual Studio, но Spark обеспечивает интеграцию с Visual Studio, включая IntelliSense и компилятор представления. Компилятор представления гарантирует, что нам не придется дожидаться исключений времени исполнения (runtime exceptions), чтобы распознать в наших представлениях опечатки и ошибки.

В данном разделе мы исследуем большинство возможностей движка Spark, чтобы выяснить преимущества данного движка над используемым по умолчанию движком представления. Но для начала давайте пройдемся по процессу установки и настройки этого движка.

Установка и настройка Spark

Последний релиз Spark можно найти на Spark сайте CodePlex (http://sparkviewengine.codeplex.com/). В данный релиз входят:

  • Сборка Spark, которая понадобится для вашего MVC проекта
  • Документация
  • Примеры
  • Программа установщик Visual Studio IntelliSense

Для того чтобы Spark запускался в вашем MVC проекте, вам необходимы только исполняемые файлы, но IntelliSense довольно полезен, поэтому перед запуском Visual Studio хорошо было бы запустить программу установщик Visual Studio IntelliSense. Далее вам необходимо добавить в ваш проект ссылки как для сборки Spark, так и для Spark.Web.Mvc, как это показано на рисунке 17-3.

Рисунок 17-3: Добавление в проект указателя на сборку Spark

После добавления в проект указателей на сборку Spark вы можете настроить ASP.NET MVC таким образом, чтобы он использовал Spark в качестве своего движка представления.

Spark обладает дополнительными настройками конфигурации, которые вы можете разместить либо в файле Web.config, либо в коде. В данном примере мы будем настраивать Spark в коде, но в документации к Spark есть полноценные примеры обоих вариантов. Ниже приведена настройка нашего движка Spark:

Листинг 17-11: Код конфигурации Spark
var settings = new SparkSettings()
	.SetDebug(true)
	.AddAssembly("SparkViewExample")
	.AddNamespace("System")
	.AddNamespace("System.Collections.Generic")
	.AddNamespace("System.Linq")
	.AddNamespace("System.Web.Mvc")
	.AddNamespace("System.Web.Mvc.Html");
ViewEngines.Engines.Add(new SparkViewFactory(settings));

Мы помещаем код конфигурации в метод Application_Start нашего файла Global.asax.cs, поскольку настройка Spark и настройка движка представления MVC должна выполняться в области приложения единожды.

В первой части кода мы создаем объект SparkSettings, настраивая режим компиляции, и добавляя сборку нашего проекта и различные компоненты для компиляции. Эта часть аналогична настройке движка представления Web Forms в файле Web.config. Далее мы добавляем новый экземпляр SparkViewFactory в коллекцию System.Web.Mvc.ViewEngines.Engines; класс ViewEngines дает возможность настраивать в вашем приложении дополнительные движки представления. Затем мы передаем наш объект SparkSettings в экземпляр SparkViewFactory. Это все, что нужно для настройки Spark.

Теперь, когда настройка Spark выполнена, мы можем перейти к созданию представлений для нашего примера.

Простой пример представления Spark

При использовании нового движка представления в части контроллера и модели вашего MVC представления вы не увидите никаких изменений.

В нашем примере нам необходимо отобразить список объектов моделей Product, как это показано ниже.

Листинг 17-12: Простая модель Product
public class Product
{
	public string Name { get; set; }
	public string Description { get; set; }
	public decimal Price { get; set; }
}

И снова движок представления Spark не помещает никаких связей ни в нашу модель, ни в наше действие контроллера, как это продемонстрировано ниже.

Листинг 17-13: ProductController для отображения объектов Product
public class ProductController : Controller
{
	public ViewResult Index()
	{
		var products = new[]
		{
			new Product {
				Name = "Toothbrush",
				Description = "Cleans your teeth",
				Price = 2.49m
			},
			new Product {
				Name = "Hairbrush",
				Description = "Styles your hair",
				Price = 10.29m
			},
			new Product {
				Name = "Shoes",
				Description = "Protects your feet",
				Price = 55.99m
		},													
	};
	return View(products);
}

Строка 5: Создает фиктивные продукты

Строка 23: Передача продуктов представлению

Мы предоставляем список фиктивных объектов Product для наших Spark представлений, которые необходимо отобразить.

Для создания наших Spark представлений мы используем структуру папок, аналогичную структуре других движков представления. В корневой папке Views мы создаем папку Product, которая соответствует нашему ProductController. Помимо этого мы создаем папки Layouts и Shared, как это показано на рисунке 17-4.

Рисунок 17-4: Окончательная структура папок для наших Spark представлений

В Spark для файлов представлений используется расширение .spark. Это, главным образом, делается для того, чтобы расширение файла не конфликтовало с другими движками представлениями в интегрированной среде разработки (IDE) или в среде выполнения.

Рисунок 17-5: Добавление макета Application.spark для наших представлений

Spark поддерживает концепцию макетов, которые эквивалентны мастер-страницам. Обычно макет по умолчанию имеет название Application.spark и располагается либо в папке Layouts, либо в Shared.

Для запуска нашего макета мы создадим текстовый файл в Visual Studio с названием Application.spark (вместо Web Form или другого шаблона). Это продемонстрировано на рисунке 17-5.

Мы выбрали шаблон Text File, поскольку нам не требуется никакой встроенной функциональности, предоставляемой к примеру шаблоном Web Forms; нам нужен всего лишь пустой файл.

Внутри нашего базового макета нам необходимо разместить пару ссылок и предоставить элемент-заполнитель для текущего дочернего контента. Наш полноценный макет продемонстрирован в следующем листинге.

Листинг 17-14: Полноценный шаблон макета Application.spark
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Spark View Example</title>
	<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
	<div class="page">
		<div id="header">
			<div id="title">
				<h1>My MVC Application</h1>
			</div>
			<div id="logindisplay">
				Welcome!
			</div>
			<div id="menucontainer">
				<ul id="menu">
					<li>${Html.ActionLink("Home", "Index", "Product")}</li>
				</ul>
			</div>
		</div>
		<div id="main">
			<use content="view" />
			<div id="footer">
			</div>
		</div>
	</div>
</body>
</html>

Первый интересный элемент в листинге 17-14 – элемент link, ссылающийся на наш CSS файл. В нем используется хорошо знакомый символ тильды (~) для обозначения базовой директории нашего веб-сайта вместо символа относительного пути (..\..\). При необходимости мы можем перебазировать наш веб-сайт и переопределить то, что обозначает символ тильды в нашей конфигурации Spark. Такой подход полезен в сценариях фермы веб-сервера (web server farm) или сети доставки контента (content-delivery network или CDN).

Следующий интересный элемент – хорошо знакомые нам вызовы Html.ActionLink, но в этот раз мы заключаем код в структуру ${}. Данный синтаксис синонимичен синтаксису <%= %> Web Forms, но если мы поместим восклицательный знак после знака доллара, т.е. вместо ${} будем использовать $!{}, то любой NullReferenceExceptions будет содержать пустой контент вместо экрана ошибки. Это одно из преимуществ движка Spark над Web Forms, где null приводит к ошибке для конечного пользователя, даже если отсутствие значений является нормальным.

Последней интересной частью нашего макета является элемент <use content="view"/>. Именованная секция контента, view, по умолчанию принимает значение имени представления нашего действия. В нашем примере это будет файл Index.spark в папке Product. Мы можем создать другие именованные секции контента для заголовка, нижнего колонтитула, боковой панели и чего-нибудь еще, что может понадобиться нам в нашем базовом макете. Мы можем вкладывать наши макеты, если это необходимо для нашего приложения, по аналогии с мастер-страницами.

После размещения макета мы можем создать представление конкретного действия.

Листинг 17-15: Spark представления для действия Index
<viewdata model="SparkViewExample.Models.Product[]" />
<var styles="new [] {'even', 'odd'}" />
<h2>Products</h2>
<table>
	<tr>
		<th>Name</th>
		<th>Price</th>
		<th>Description</th>
	</tr>
	<var i="0">
		<tr each="var product in ViewData.Model" class="${styles[i%2]}">
			<td>${product.Name}</td>
			<td>${product.Price}</td>
			<td>${product.Description}</td>
			<set i="i+1" />
		</tr>
	</var>
</table>

В представлении Index нам необходимо выполнить цикл по всем Products в модели, отображая строку для каждого Product. Что касается Web Forms, то нам нужно было бы поместить наш цикл for в блоки <% %> кода, но при использовании Spark у нас есть более корректные варианты. В начале мы используем элемент <viewdata />, чтобы указать Spark, что мы используем строго типизированное представление и что типом нашей модели является массив Products. Spark также поддерживает словарь ViewData, в основе которого лежат ключи. Далее мы создаем локальную переменную styles с элементом <var />. Каждое имя атрибута становится новой локальной переменной, а значение атрибута – присвоенным значением. Эти две переменные помогут нам создать стили чередующихся строк.

Затем мы поместим обычный HTML в наше представление, включая заголовок, таблицу, строку заголовка. В Spark в специальные Spark XML элементы вкрапляются HTML элементы, заставляя наше представление выглядеть более корректным, без сбивающих с толку угловых скобок языка C#. После строки заголовка мы создаем переменную-счетчик для содействия стилям чередующихся строк.

Нам необходимо выполнить цикл по всем Products нашей модели, создавая строку для каждого элемента. В Web Forms это достигается путем использования цикла foreach, но в Spark нам необходимо только добавить атрибут each к HTML элементу, который мы хотим повторить, давая фрагменту кода C# выполнять цикл по каждому значению атрибута. Элементу class в нашем элементе-строке присваивается чередующийся стиль, с использованием при этом счетчика для переключения между нечетными и четными стилями.

Внутри нашей строки мы используем структуру ${} для отображения каждого индивидуального продукта. Поскольку мы установили Spark Visual Studio Integration, то мы получили IntelliSense в наших представлениях, как это продемонстрировано на рисунке 17-6.

Рисунок 17-6: Использование IntelliSense в наших представлениях возможно благодаря расширению Visual Studio

Для завершения создания стилей чередующихся строк мы увеличиваем на единицу счетчик посредством элемента <set />. Этот элемент позволяет нам присвоить значения переменным, которые мы создали ранее в нашем представлении. Помимо атрибута each и элемента <set />, Spark предоставляет сложные выражения для условных операторов (if ... else), макросов и прочего.

После завершения создания Spark представления наше представление отображается, как и предполагалось, в веб-браузере, как это показано на рисунке 17-7.

Рисунок 17-7: Наше запущенное Spark приложение

Благодаря архитектуре ASP.NET MVC мы можем выгружать движки представления без необходимости изменения наших контроллеров или действий. Как мы поняли из данного раздела на примере движка представления Spark, многие движки представления обеспечивают более корректный способ создания представлений в MVC приложениях. Движок представления Spark предоставляет нам более лаконичную и более читаемую разметку, код смешивания и прозрачный HTML. Поскольку Spark поддерживает компилируемые представления и IntelliSense, нам не нужно отказываться от приятных возможностей интеграции, которые предоставляет Web Forms.

Решение о выборе другого движка представления все еще остается довольно важным, поскольку оно имеет долгосрочные технические и нетехнические последствия. Альтернативные движки представления должны быть еще одной возможностью изучения MVC приложений, поскольку эти движки предоставляют привлекательные альтернативы используемых по умолчанию движков представления Web Forms и Razor.