|
|
|||||||||||||||||||||||||||||
|
Введение в одностраничные приложения для .NET-разработчиковИсточник: msdnmicrosoftcom
Исходный код можно скачать по ссылке. Продукты и технологии: ASP.NET MVC 5, JavaScript, одностраничные приложения, Kendo UI, RequireJS, Entity Framework, Web API, OData В статье рассматриваются:
Большинство разработчиков, использующих Microsoft .NET Framework, большую часть своего времени занималось серверной стороной, создавая веб-приложения на C# или Visual Basic .NET. Конечно, JavaScript применяли для простых вещей вроде модальных окон, проверки, AJAX-вызовов и т. д. Однако JavaScript (в основном на клиентской стороне) использовался как вспомогательный язык, а приложения работали главным образом на серверной стороне. Не так давно проявилась тенденция к миграции кода веб-приложений с серверной стороны на клиентскую (в браузеры), отвечающая ожиданиям в появлении гибких и отзывчивых пользовательских сред. А раз так, то множеству .NET-разработчиков (особенно корпоративных) пришлось резко озаботиться рекомендациями по программированию на JavaScript, архитектурой, модульным тестированием, поддержкой сопровождения и разбираться со всевозможными видами JavaScript-библиотек, которых становится все больше и больше. Отчасти тенденция с переходом на клиентскую сторону связана с растущим использованием одностраничных приложений (single-page applications, SPA). Сказать, что разработка SPA - это будущее, было бы сильным преуменьшением. Именно SPA являются примером некоторых из лучших веб-приложений, которые обеспечивают гибкие и отзывчивые пользовательские среды, в то же время сводя к минимуму объемы данных (трафик) и частоту полных циклов обмена ими между клиентом и сервером. Сказать, что разработка SPA - это будущее, было бы сильным преуменьшением. В этой статье я рассмотрю проблемы, которые могут возникнуть при переходе с серверной стороны в царство SPA. Лучший способ справиться с этими проблемами - принять язык JavaScript как полноценный и ничем не уступающий любым другим .NET-языкам, таким как C#, Visual Basic .NET, Python и др. Ниже перечислены некоторые фундаментальные принципы .NET-разработки, которые иногда игнорируются или упускаются из виду при создании приложений на JavaScript:
Поскольку эта статья адресована .NET-разработчикам, которые только знакомятся с миром SPA, я буду включать минимум инфраструктур - ровно столько, сколько необходимо для создания управляемого SPA с хорошей архитектурой. Семь основных этапов создания SPAРассмотрим семь основных этапов преобразования нового ASP.NET Web Application, созданного с использованием готового шаблона ASP.NET MVC в Visual Studio 2013, в SPA (со ссылками на соответствующие файлы проекта, которые можно найти в сопутствующем этой статье пакете кода).
Я покажу, как создать впечатляющее SPA-приложение в ASP.NET MVC с использованием следующих JavaScript-библиотек, доступных через NuGet.
Подготовка инфраструктуры SPAЧтобы показать, как подготовить инфраструктуру SPA, я сначала поясню, как создать модуль конфигурации RequireJS (Northwind.Web/Scripts/app/main.js). Этот модуль будет стартовой точкой входа в приложение. Если вы создали консольное приложение, можете рассматривать его как точку входа Main в Program.cs. В основном он содержит первый класс и метод, вызываемый при запуске SPA. Файл main.js главным образом служит манифестом SPA и является тем местом, где вы определяете все, что будет в SPA, и их зависимости, если таковые есть. Код для конфигурации RequireJS показан на Рис. 2. Рис. 2. Конфигурация RequireJS
У вас есть два варианта представлений, которые будут загружаться в SPA: стандартные HTML-страницы (*.html) или страницы ASP.NET MVC Razor (*.cshtml). На Рис. 2 свойство paths содержит список всех модулей с местами их расположения и именами. Shim - это имя ранее определенного модуля. Свойство shim включает любые зависимости, которые могут быть у модуля. В данном случае вы загружаете модуль kendo, и у него есть зависимость от модуля jquery, поэтому, если какой-то модуль требует модуля kendo, сначала загружайте jQuery. Код "require([], function(){})" на Рис. 2 загрузит следующий модуль, каковым будет модуль с именем app. Заметьте, что я присваиваю модулям осмысленные имена. Итак, каким образом ваше SPA узнает, какой модуль следует вызвать первым? Вы настраиваете это на первой посадочной странице (landing page) в SPA с помощью атрибута data-main в теге script со ссылкой на RequireJS. Я указал, что это должен быть модуль main (main.js). RequireJS возьмет на себя всю черновую работу, связанную с загрузкой этого модуля; вы просто сообщаете, какой модуль загружать первым. У вас есть два варианта представлений, которые будут загружаться в SPA: стандартные HTML-страницы (*.html) или страницы ASP.NET MVC Razor (*.cshtml). Так как эта статья адресована .NET-разработчикам (и во многих организациях есть серверные библиотеки и инфраструктуры, которыми они хотели бы по-прежнему использовать в своих представлениях), я выбираю вариант с созданием Razor-представлений. Начну с добавления представления и назову его Spa.cshtml, как уже упоминалось. Это представление будет в основном загружать оболочку или весь HTML для разметки SPA. Из этого представления я буду загружать другие представления (например, About.cshtml, Contact.cshtml, Index.cshtml и т. д.) с заменой по мере того, как пользователь будет переходить по SPA; при этом очередное представление заменяет весь HTML в теге div контента. Создание посадочной страницы SPA (разметки) (Northwind.Web/Views/Spa.cshtml) Поскольку представление Spa.cshtml является посадочной страницей SPA, где вы загружаете все остальные представления, в нем не будет особой разметки, кроме ссылки на необходимые таблицы стилей и RequireJS. Обратите внимание на атрибут data-main в следующем коде, который сообщает RequireJS, какой модуль следует загрузить первым:
Добавление действия для SPA Layout (Northwind.Web/Controllers/HomeController.cs) Чтобы создать и загрузить представление Spa.cshtml, добавьте действие (action) и представление:
Создание модуля приложения (Northwind.Web/Scripts/app/app.js) Вот модуль приложения, отвечающий за инициализацию и запуск Kendo UI Router:
Создание модуля router (Northwind.Web/Scripts/app/router.js) Вызывается модулем app.js. Если вы уже знакомы с маршрутами в ASP.NET MVC, то ничего нового для вас здесь нет. Это маршруты SPA для ваших представлений. Я определю все маршруты для всех SPA-представлений, и, когда пользователь будет переходить по SPA, модуль router в Kendo UI будет знать, какие представления надо загружать в SPA (см. листинг 1 в пакете сопутствующего кода). Класс Router в Kendo UI отвечает за отслеживание состояния приложения и навигацию между его состояниями. Этот модуль (router) интегрируется в журнал браузера, используя элемент фрагмента в URL (#page), что позволяет создавать закладки и ссылки на состояния приложения. При щелчке маршрутизируемого URL в дело вступает модуль router и сообщает приложению перевести себя обратно в то состояния, которое закодировано в маршруте. Определение маршрута - это строка, представляющая путь для идентификации состояния приложения, которое хочет увидеть пользователь. Когда определение маршрута совпадает с фрагментом хеша URL браузера, вызывается обработчик маршрута (табл. 1). Табл. 1. Определения зарегистрированных маршрутов и соответствующие URL
Что касается виджета разметки Kendo UI, то его название говорит само за себя. По-видимому, вы знакомы с ASP.NET Web Forms MasterPage или MVC-разметкой, включаемой при создании нового проекта ASP.NET MVC Web Application. В проекте SPA разметка помещается в Northwind.Web/Views/Shared/_Layout.cshtml. Разметка в Kendo UI и MVC отличается немного - за исключением того, что разметка Kendo UI выполняется на клиентской стороне. Как и разметка, работающая на серверной стороне, где исполняющая среда MVC заменяет содержимое разметки другими представлениями, разметка в Kendo UI действует точно так же, но на клиентской стороне. Вы выгружаете представление (контент) разметки Kendo UI, используя метод showIn. Содержимое представления (HTML) будет помещаться в div с идентификатором content, который передается в разметку Kendo UI при ее инициализации. После инициализации разметки выполняется ее рендеринг в div с идентификатором app, который является div в посадочной странице (Northwind.Web/Views/Home/Spa.cshtml). Я вкратце опишу это. Класс Router в Kendo UI отвечает за отслеживание состояния приложения и навигацию между его состояниями. Вспомогательный метод loadView принимает модель представления, представление и при необходимости обратный вызов, запускаемый, как только происходит связывание представления и модели представления. В методе loadView вы используете библиотеку Kendo UI FX, позволяющую улучшить эстетическое восприятие UI за счет добавления некоторых простых анимаций в процесс замены представлений. Это осуществляется скольжением текущего загруженного представления влево, удаленной загрузкой нового представления и его последующим скольжением обратно в центр. Очевидно, что эту анимацию можно легко заменять на любые другие, используя библиотеку Kendo UI FX. Одно из важнейших преимуществ применения разметки Kendo UI проявляется при вызове метода showIn для выгрузки представлений. Он гарантирует выгрузку представления, его корректное уничтожение и удаление из DOM браузера, что обеспечивает масштабируемость и производительность SPA. Редактирование представления _ViewStart.cshtml (Northwind.Web/Views/_ViewStart.cshtml) Вот как настроить все представления, чтобы по умолчанию они не использовали разметку ASP.NET MVC:
К этому моменту SPA должно работать. Щелкнув любую из навигационных ссылок в меню, вы увидите, что текущий контент выгружается через AJAX благодаря модулю router из Kendo UI и RequireJS. Эти семь этапов, необходимых для преобразования нового ASP.NET Web Application в SPA, не так уж и страшны, не правда ли? Теперь, когда SPA подготовлено и работает, я займусь тем, что делает большинство разработчиков с такими приложениями, а именно добавлю в него CRUD-функциональность. Добавление CRUD-функциональности в SPAНиже перечислены основные этапы, необходимые для добавления представления сетки Customer в SPA (и связанных файлов кода проекта). Итак, добавьте:
Разметка в Kendo UI и MVC отличается немного - за исключением того, что разметка Kendo UI выполняется на клиентской стороне. Подготовка структуры решения с помощью Entity Framework На рис. 3 показана структура решения, где выделены три проекта: Northwind.Data (1), Northwind.Entity (2) и Northwind.Web (3). Я вкратце рассмотрю каждый из них наряду с Entity Framework Power Tools.
Примечание SQL-скрипт установки Northwind и резервная копия базы данных включены в пакет сопутствующего кода в папку Northwind.Web/App_Data (bit.ly/1cph5qc). Теперь, когда решение настроено на доступ к базе данных, напишем MVC-класс CustomerController.cs, который будет обслуживать представления Index и Edit. Поскольку единственная обязанность контроллера - обслуживать HTML-представление для SPA, здесь код будет минимальным. Создание MVC-контроллера Customer (Northwind.Web/Controllers/CustomerController.cs) Вот как создать контроллер Customer с действиями для представлений Index и Edit:
Создание представления с сеткой Customers (Northwind.Web/Views/Customers/Index.cshtml) Нарис. 4 показано, как создать представление с сеткой Customers. Если разметка на Рис. 4 вам не знакома, не паникуйте: это разметка Kendo UI MVVM (HTML). Она просто конфигурирует HTML-элемент, в данном случае - div с идентификатором grid. Позднее, когда вы свяжете это представление с моделью представления, используя инфраструктуру Kendo UI MVVM, эта разметка будет преобразована в виджеты Kendo UI. Подробнее на эту тему см. по ссылкеbit.ly/1d2Bgfj. Рис. 4. Разметка представления сетки Customer с помощью виджета MVVM и привязки событий
Создание контроллера Customer MVC (OData) Web API (Northwind.Web/Api/CustomerController.cs) Теперь я покажу, как создать контроллер Customer. OData - это протокол доступа к данным для Web, который предоставляет единообразный способ запроса и манипулирования наборами данных через CRUD-операции. С помощью ASP.NET Web API создать конечную точку OData довольно легко. Вы можете контролировать то, какие OData-операции будут доступны. Вы можете разместить несколько конечных точек OData наряду с конечными точками, не имеющими отношения к OData. Вы получаете полный контроль над своей моделью данных, серверной бизнес-логикой и уровнем данных. Код для контроллера Customer Web API OData приведен на Рис. 5. Рис. 5. Контроллер Customer Web API OData
Код на Рис. 5 просто создает контроллер OData Web API для предоставления данных Customer из базы данных Northwind. После его создания вы можете запустить проект, а с помощью таких средств, как Fiddler (бесплатный веб-отладчик на fiddler2.com) или LINQPad, можно запрашивать сами данные по клиенту (customer). Настройка и предоставление OData из таблицы Customer для сетки (Northwind.Web/App_Start/WebApiConfig.cs) На рис. 6 настраивается и предоставляется OData из таблицы Customer для сетки. Рис. 6. Настройка маршрутов ASP.NET MVC Web API для OData
Запросы OData Web API с помощью LINQPad Если вы еще не пользовались LINQPad (linqpad.net), добавьте это средство в свой инструментарий разработки; это необходимый инструмент, доступный в бесплатной версии. На рис. 7 показан LINQPad с подключением к Web API OData (localhost:2501/odata), отображающий результаты LINQ-запроса "Customer.Take (100)".
Создание (наблюдаемой) модели Customer (Northwind.Web/Scripts/app/models/customerModel.js) Далее мы создаем модель Customer (Kendo UI Observable). Ее можно считать моделью сущности Customer на клиентской стороне. Я создал такую модель, поэтому ее можно будет повторно использовать в представлениях сетки и редактирования Customer. Код приведен на Рис. 8. Рис. 8. Создание модели Customer (Kendo UI Observable)
OData - это протокол доступа к данным для Web, который предоставляет единообразный способ запроса и манипулирования наборами данных через CRUD-операции. Создание DataSource для сетки Customers (Northwind.Web/Scripts/app/datasources/customersDatasource.js) Если вы знакомы с источниками данных из ASP.NET Web Forms, то знайте, что здесь используется та же концепция, где вы создаете источник данных для сетки Customers (Northwind.Web/Scripts/app/datasources/customersDatasource.js). Компонент Kendo UI DataSource (bit.ly/1d0Ycvd) - это абстракция для использования локальных данных (массивов JavaScript-объектов) или удаленных (XML, JSON или JSONP). Он полностью поддерживает CRUD-операции над данными и предоставляет как локальную, так и серверную поддержку сортировки, разбиения на страницы, фильтрации, группирования и агрегации. Создание ViewModel для представления сетки Customers Это та же концепция, что и MVVM в Windows Presentation Foundation (WPF) или Silverlight, но на клиентской стороне (находится в этом проекте в Northwind.Web/Scripts/ViewModels/Customer/indexViewModel.cs). MVVM - архитектурный шаблон, отделяющий представление от его данных и бизнес-логики. Вскоре вы увидите, что все данные, бизнес-логика и прочее содержатся в модели представления и что представление является чистым HTML (презентационным уровнем). Код для представления сетки Customer показан на Рис. 9. Рис. 9. Модель представления сетки Customer
Я кратко опишу различные компоненты кода на рис. 9.
Теперь добавьте модули customerModel, indexViewModel и customersDatasource в свою конфигурацию RequireJS (Northwind.Web/Scripts/app/main.js). Код показан на рис. 10. Рис. 10. Добавления в конфигурацию RequireJS
Добавление маршрута для нового представления сетки Customers Заметьте, что в обратном вызове loadView (в Northwind.Web/Scripts/app/router.js) вы связываете панель инструментов сетки после ее инициализации и выполнения MVVM-привязки. Дело в том, что при первом связывании сетки панель инструментов не инициализируется, поскольку она уже существует в сетке. При первой инициализации сетки через MVVM она будет загружать панель инструментов из шаблона Kendo UI. После ее загрузки в сетку вы связываете панель инструментов только со своей моделью представления, чтобы кнопки на панели инструментов были связаны с методами save и cancel в вашей модели представления. Вот как выглядит код, регистрирующий определение маршрута для представления редактирования Customer:
Теперь у вас есть полнофункциональное представление сетки Customers. Загрузите localhost:25061/Home/Spa#/customer/index (номер порта на вашем компьютере скорее всего будет другим) в браузер и вы увидите то, что показано на рис. 11.
Подключение представления редактирования Customer Основные этапы добавления представления редактирования Customer в SPA:
Поскольку вы используете инфраструктуру Kendo UI, примените стили Kendo UI к своему представлению редактирования. Узнать больше на эту тему можно по ссылке bit.ly/1f3zWuC. На Рис. 12 показана разметка представления редактирования с помощью виджета MVVM и связывания с событиями. Рис. 12. Разметка представления редактирования с помощью виджета MVVM Widget и связывания с событиями
Создание модуля util для получения идентификатора Customer из URL Поскольку вы создаете модули с четкими границами, чтобы добиться хорошего разделения обязанностей, я продемонстрирую, как создать модуль util, где будут находиться все ваши вспомогательные функции (методы). Начну с метода, который может извлекать идентификатор клиента из URL для Customer DataSource (Northwind.Web/Scripts/app/datasources/customerDatasource.js), как показано на рис. 13. Рис. 13. Модуль util
Добавление модели представления edit и модулей util в конфигурацию RequireJS (Northwind.Web/Scripts/app/main.js) Код на рис. 14 показывает добавления в конфигурацию RequireJS для модулей редактирования Customer. Рис. 14. Добавления в конфигурацию RequireJS для модулей редактирования Customer
Добавление модели представления для редактирования Customer (Northwind.Web/Scripts/app/viewModels/editViewModel.js) Код на рис. 15 демонстрирует, как добавить модель представления для редактирования Customer. Рис. 15. Модуль модели представления для редактирования Customer
Я кратко опишу различные компоненты кода на рис. 15.
Когда RequireJS загружает какой-то модуль, код в теле метода define будет вызван только раз, поэтому вы предоставляете некий метод (loadData) в своей модели представления редактирования, чтобы иметь механизм загрузки данных после того, как модуль модели представления редактирования уже загружен (это можно увидеть в Northwind.Web/Scripts/app/router.js). Добавление маршрута для нового представления редактирования Customer (Northwind.Web/Scripts/app/router.js) Вот как добавляется маршрут:
Заметьте: когда модель представления редактирования Customer запрашивается от RequireJS, вы можете извлечь Customer, вызвав метод loadData из этой модели представления. Это позволяет загружать корректные данные Customer по идентификатору в URL всякий раз, когда загружается представление редактирования Customer. Маршрут не обязательно "зашивать" в код как строку. Кроме того, он может содержать параметры, такие как серверный маршрутизатор (Ruby on Rails, ASP.NET MVC, Django и др.). Для этого укажите в сегменте маршрута двоеточие перед именем нужной переменной. Теперь вы можете загрузить представление редактирования Customer в браузер (localhost:25061/Home/Spa#/customer/edit/ANATR) и увидеть экран, как на рис. 16.
Примечание Хотя функциональность delete в представлении сетки Customer была подключена, при щелчке кнопки Delete на панели инструментов (рис. 17) появится исключение, показанное на Рис. 18.
Это исключение так и задумано, поскольку большинство идентификаторов Customer являются внешними ключами в других таблицах, например Orders, Invoices и т. д. Вы должны были бы подключить каскадное удаление, которое удаляло бы все записи изо всех таблиц, где данный Customer ID является внешним ключом. И хотя вы не в состоянии удалить что-либо, я все же хотел показать этапы создания функциональности удаления и ее код. Ну, вот и все. Я продемонстрировал, как легко и быстро преобразовывать готовое ASP.NET Web Application в SPA с помощью RequireJS и Kendo UI. Затем я показал, насколько легко добавить CRUD-подобную функциональность в SPA. Вы можете увидеть активную демонстрацию этого проекта по ссылке bit.ly/1bkMAlK и скачать код с сайта проектов CodePlex на easyspa.codeplex.com. Удачи в кодировании! Лонг Ле (Long Le) - главный архитектор .NET-разработок в CBRE Inc. и обладатель звания Telerik/Kendo UI MVP. Большую часть времени занимается разработкой инфраструктур и блоков приложений, руководит внедрением передового опыта и шаблонов, а также отвечает за стандартизацию корпоративного стека технологий. Более десяти лет работает с технологиями Microsoft. В свободное время ведет блог (blog.longle.net) и играет в Call of Duty. Также следите за его заметками в twitter.com/LeLong37. Выражаю благодарность за рецензирование статьи экспертам Дерику Бэйли (Derick Bailey) из Telerik и Майку Уоссону (Mike Wasson) из Microsoft.
|
|