Работающий программист

Приступаем к работе с Oak: другой подход

Тэд Ньюард

Тэд НьюардКак я обсуждал в прошлый раз, проект Oak — это веб-инфраструктура, включающая динамические подходы, которые распространены в инфраструктурах, в большей мере ориентированных на динамические языки (например, Ruby on Rails или любые веб-инфраструктуры MVC в Node.js вроде Express или Tower). Поскольку Oak основана на Microsoft .NET Framework и использует такие части C#, как ключевое слово dynamic и Dynamic Language Runtime (DLR), в ней применяется подход к разработке веб-приложений, отличающийся от привычного в традиционной разработке на основе ASP.NET MVC. По этой причине, как вы узнали в предыдущей статье, получение необходимого ПО для разработки с применением Oak несколько сложнее обычного скачивания NuGet-пакета.

Предполагая, что вы читали предыдущую статью (msdn.microsoft.com/magazine/dn451446), скачали и установили все необходимое, запустили непрерывную фоновую компиляцию и получили начальную сборку, выполняемую на вашем компьютере (в IIS Express, порт 3000, как вы помните), пора приступать к работе в Oak.

Запуск

Если Oak не выполняется на вашем компьютере, выполните команды rake и rake server в командной строке просто, чтобы убедиться, что все в порядке. Затем запустите sidekick (если она еще не выполняется) и откройте браузер по адресу localhost:3000, как показано на рис. 1.

Окно справки проекта Oak
Рис. 1. Окно справки проекта Oak

Как предполагают учебные материалы, изучение Oak осуществляется как своего рода прохождение в навигационном стиле (breadcrumbs-style walkthrough). Но, прежде чем я перейду к этому, взгляните на структуру проекта (рис. 2).

Структура проекта Oak в Visual Studio Solution Explorer
Рис. 2. Структура проекта Oak в Visual Studio Solution Explorer

Начальный проект (seed project) состоит из двух проектов: проекта ASP.NET MVC и проекта с тестами для решения. MVC-проект является традиционным приложением ASP.NET MVC с добавленной папкой Oak, которая содержит файлы исходного кода, образующие Oak-части проекта. Это делает тривиальной задачу пошагового выполнения Oak-частей кода при отладке и в духе всех проектов с открытым исходным кодом также позволяет вносить локальные изменения (если и когда это необходимо). В настоящее время в проекте нет моделей, есть три контроллера и всего пара представлений. Важнее то, что первый запрос по конечной точке дает ошибку, сообщающую, что представление Index.cshtml (или аналогичное) не существует. Загрузчик Oak предлагает два этапа. Сначала вы должны создать два новых типа: Blog и Blogs (набор экземпляров Blog). Вызов класса Blogs обеспечивает простой, основанный на соглашении доступ к таблице Blogs в базе данных:

public class Blogs : DynamicRepository
{
}
// Это динамическая сущность, представляющая блог
public class Blog : DynamicModel
{
public Blog() { }
public Blog(object dto) : base(dto) { }
}

Затем в HomeController следует внести некоторые изменения, чтобы он мог отвечать на различные присылаемые HTTP-запросы, как показано на рис. 3.

Рис. 3. Ответы на разные HTTP-запросы

public class HomeController : Controller
{
// Инициализируем блог
Blogs blogs = new Blogs();
public ActionResult Index()
{
// Возвращаем все блоги из базы данных
ViewBag.Blogs = blogs.All();
return View();
}
// Операция контроллера для сохранения блога
[HttpPost]
public ActionResult Index(dynamic @params)
{
dynamic blog = new Blog(@params);
...

Большая часть этого будет знакома разработчикам, использующим ASP.NET. Разительное отличие в том, что все типизируется C#-типом dynamic, а не Blog или Blogs. Сам тип Blog не имеет полей или свойств. В типе Blogs — агрегате экземпляров Blog — аналогичным образом нет объявленного кода для вставки, удаления, перечисления, замены или выполнения любых других операций, часто связываемых с наборами.

Большая часть этой функциональности берется из библиотеки Gemini, основанной на типе dynamic, — основной части проекта Oak (о ней я рассказывал в своей статье «Going Dynamic with the Gemini Library» в номере на август 2013 г.; msdn.microsoft.com/magazine/dn342877). Blog расширяет базовый класс DynamicModel, а это фактически означает, что вы можете программировать с его использованием, не определяя заранее модель. Любое поле, на которое вы ссылаетесь в любом конкретном экземпляре Blog, будет на месте, даже если вы никогда ранее не ссылались на него. В этом мощь динамического программирования. Аналогично Blogs — это DynamicRepository. Как таковой, он уже знает, как хранить и манипулировать объектами DynamicModel.

Еще интереснее то, что Oak изначально известно, как хранить экземпляры Blog в SQL-таблице (которая, как это ни удивительно, называется «Blogs»). Она не только создаст схему базы данных при первом использовании, но и позволит заполнить базу данных любыми начальными данными, необходимыми системе.

При конструировании экземпляр Blog принимает динамический объект как параметр. Конструктор базового класса знает, как пройти по любым динамически определенным полям/свойствам в этом объекте. Аналогично экземпляру Blogs тоже известно, как перебирать все динамически определенные поля/свойства в экземпляре Blog. Он будет хранить их в базе данных (при вызове blog.Insert). Кроме того, он умеет получать экземпляр Blog из базы данных через поле BlogId. Все это делается кодом на рис. 3; никакого дополнительного кода для модели не требуется — по крайней мере, не сейчас. (Есть многое другое, что вам может понадобиться, но пока больше ничего не нужно.)

Кстати, если вас интересует, что такое оператор @, вспомните, что params — это на самом деле зарезервированное слово в C#. Чтобы использовать его как допустимое имя параметра, нужно добавлять префикс @, и тогда компилятор C# не станет интерпретировать его как ключевое слово.

После модификации HomeController.cs следующий шаг — создание представления Index.cshtml в папке Home, вложенной в папку Views. Оно будет показывать результаты работы контроллера (рис. 4).

Рис. 4. Создание представления

@{
ViewBag.Title = "Index";
}
<h2>Hello World</h2>
<div>
If this page came up successfully, you're doing well! Go ahead
and create a blog (try to create blogs with duplicate names).
</div>
<br />
@using (Html.BeginForm())
{
@Html.TextBox("Name")
<input type="submit" value="create" />
}
@foreach (var blog in ViewBag.Blogs)
{
<div>
<pre>@blog</pre>
<br />
<div>
Almost there, you have comments listing; let's try to add one.
</div>
<br />
</div>
}

На первый взгляд это представление не является просто одним из представлений ASP.NET. И вновь в игру вступает динамическая природа системы. Ни один экземпляр Blog не определяет поле Name в типе Blog, но когда форма передается системе, параметр «name=...» передается HomeController. Этот контроллер затем перешлет пару «имя-значение» в переменной @params, используемой для инициализации экземпляра Blog. Безо всякой дополнительной работы с вашей стороны в экземпляре Blog теперь его поле/свойство Name.

Непрерывная непрерывность

Если вы играете в домашнюю версию этой игры и сохранили эти файлы, вы увидите нечто интересное (рис. 5).

Уведомление Growl, показывающее уведомление об успешной сборке
Рис. 5. Уведомление Growl, показывающее уведомление об успешной сборке

Прежде всего в нижнем правом углу выскакивает уведомление. Это работает Growl. Он выдает вам светло-зеленое уведомление о том, что ранее запущенное вами приложение sidekick, которое начало процесс сборки, успешно завершилось. Если же оно по какой-то причине потерпит неудачу, значок на левой стороне окна уведомления будет красным, и в нем будет показан консольный вывод. Далее, если вы посмотрите на консольное окно, в котором выполняется sidekick, вам станет понятно, что произошло. Средство наблюдения за файловой системой в каталоге Blog зарегистрировало изменение файла исходного кода (поскольку вы сохранили его). Тогда sidekick воспримет это как намек на необходимость собрать проект заново.

Предполагая, что файлы сохранены и код в них корректен, переход по localhost:3000 даст новый результат (рис. 6).

Oak не может делать кирпичи без глины
Рис. 6. Oak не может делать кирпичи без глины

На этот раз Oak пытается подключиться к выполняемому экземпляру SQL Server, чтобы извлечь данные из таблицы Blog. Кроме того, Oak старается автоматически управлять ORM-частью (object-relation mapping) проекта за вас, и об этом я расскажу в следующий раз.

Другой стиль

Как видите, использование Oak определенно требует другого стиля разработки. Ни на одном из этапов вам не приходится делать что-то более сложное в Visual Studio, чем открыть файл, изменить его содержимое, сохранить новую версию и добавить новый файл в проект. Также от вас не требуется самостоятельно инициировать сборку и запускать Visual Studio или открывать Server Explorer, чтобы создать таблицы или выполнить скрипты SQL Server.

Все это по-прежнему доступно вам, если в том возникнет необходимость. И вновь Oak — это просто уровень (причем довольно тонкий) поверх традиционного стека ASP.NET. Однако этот уровень обеспечивает скорость разработки и продуктивность труда, сходные с таковыми в более динамических средах, но без потери всего того, что вам нравится в мире статической типизации.

Oak позволяет делать гораздо больше, но это мы отложим на будущее.

Удачи в кодировании!


Тэд Ньюард (Ted Neward) — глава компании Neward & Associates LLC. Автор и соавтор многочисленных книг, в том числе «Professional F# 2.0» (Wrox, 2010), более сотни статей, часто выступает на многих конференциях по всему миру; кроме того, имеет звание Microsoft MVP в области F#. С ним можно связаться по адресу ted@tedneward.com, если вы заинтересованы в сотрудничестве. Также читайте его блог blogs.tedneward.com и заметки в twitter.com/tedneward.

Выражаю благодарность за рецензирование статьи эксперту Амиру Раджану (Amir Rajan) (автор проекта Oak).