Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Шаблон Knockout MVC является частью ASP.NET и Web Tools 2012.2
Обновление ASP.NET и веб-инструментов 2012.2 включает шаблон приложения Single-Page (SPA) для ASP.NET MVC 4. Этот шаблон предназначен для быстрого создания интерактивных клиентских веб-приложений.
"Одностраничные приложения" (SPA) — это общий термин веб-приложения, который загружает одну HTML-страницу, а затем динамически обновляет страницу, а не загружает новые страницы. После начальной загрузки страницы SPA взаимодействует с сервером с помощью запросов AJAX.
AJAX не является новым, но сегодня существуют платформы JavaScript, которые упрощают сборку и обслуживание большого сложного приложения SPA. Кроме того, HTML 5 и CSS3 упрощают создание расширенных пользовательских интерфейсов.
Чтобы приступить к работе, шаблон SPA создает пример приложения "Список действий". В этом руководстве мы рассмотрим шаблон. Сначала мы рассмотрим само приложение списка задач, а затем изучим технологические компоненты, которые обеспечивают его работу.
Создание проекта шаблона SPA
Требования:
- Visual Studio 2012 или Visual Studio Express 2012 для Интернета
- обновление ASP.NET Web Tools 2012.2. Вы можете установить обновление здесь.
Запустите Visual Studio и выберите новый проект на начальной странице. Или в меню "Файл " выберите "Создать " и " Проект".
В области "Шаблоны " выберите "Установленные шаблоны " и разверните узел Visual C# . В разделе Visual C# выберите "Веб". В списке шаблонов проектов выберите ASP.NET веб-приложение MVC 4. Присвойте проекту имя и нажмите кнопку "ОК".
В мастере создания проекта выберите одностраничные приложения.
Нажмите клавишу F5, чтобы создать и запустить приложение. При первом запуске приложения отображается экран входа.
Щелкните ссылку "Регистрация" и создайте нового пользователя.
После входа приложение создает список todo по умолчанию с двумя элементами. Чтобы добавить новый список, можно нажать кнопку "Добавить список todo".
Переименуйте список, добавьте элементы в список и проверьте их. Вы также можете удалить элементы или удалить весь список. Изменения автоматически сохраняются в базе данных на сервере (фактически LocalDB на этом этапе, так как приложение выполняется локально).
Архитектура шаблона SPA
На этой схеме показаны основные стандартные блоки для приложения.
На стороне сервера ASP.NET MVC обслуживает HTML-код, а также обрабатывает проверку подлинности на основе форм.
ASP.NET веб-API обрабатывает все запросы, связанные с ToDoLists и ToDoItems, включая получение, создание, обновление и удаление. Клиент обменивается данными с веб-API в формате JSON.
Entity Framework (EF) — это уровень O/RM. Он является посредником между объектно-ориентированным миром ASP.NET и базовой базой данных. База данных использует LocalDB, но ее можно изменить в файле Web.config. Обычно для локальной разработки используется LocalDB, после чего применяется миграция Entity Framework с методом code-first для развертывания базы данных SQL на сервере.
На стороне клиента библиотека Knockout.js обрабатывает обновления страниц из запросов AJAX. Knockout использует привязку данных для синхронизации страницы с актуальными данными. Таким образом, вам не нужно писать код, который проходит по данным JSON и обновляет DOM. Вместо этого вы помещаете декларативные атрибуты в HTML, которые сообщают Нокауту, как представить данные.
Большое преимущество этой архитектуры заключается в том, что он отделяет слой презентации от логики приложения. Вы можете создать часть веб-API, не зная ничего о том, как будет выглядеть веб-страница. На стороне клиента создается "модель представления" для представления данных, а модель представления использует Нокаут для привязки к HTML. Это позволяет легко изменять HTML-код, не изменяя модель представления. (Мы рассмотрим Knockout немного позже.)
Модели
В проекте Visual Studio папка Models содержит модели, используемые на стороне сервера. (Существуют также клиентские модели; мы также рассмотрим их.)
TodoItem, TodoList
Это модели базы данных для Entity Framework Code First. Обратите внимание, что эти модели имеют свойства, указывающие друг на друга.
ToDoList содержит коллекцию ToDoItems, и каждый ToDoItem имеет ссылку на родительский ToDoList. Эти свойства называются свойствами навигации, и они представляют отношение "один ко многим" между списком задач и его пунктами.
Класс ToDoItem также использует атрибут [ForeignKey] , чтобы указать, что ToDoListId это внешний ключ в ToDoList таблице. Это указывает EF добавить ограничение внешнего ключа в базу данных.
[ForeignKey("TodoList")]
public int TodoListId { get; set; }
public virtual TodoList TodoList { get; set; }
TodoItemDto, TodoListDto
Эти классы определяют данные, которые будут отправляться клиенту. DTO означает "объект передачи данных". DTO определяет, как сущности будут сериализованы в JSON. Как правило, существует несколько причин использования DTOs:
- Для управления тем, какие свойства сериализуются. DTO может содержать подмножество свойств из модели домена. Это можно сделать по соображениям безопасности (чтобы скрыть конфиденциальные данные) или просто сократить объем отправляемых данных.
- Чтобы изменить форму данных, например, для выравнивания более сложной структуры данных.
- Чтобы сохранить любую бизнес-логику вне DTO (разделение проблем).
- Если модели домена не могут быть сериализованы по какой-то причине. Например, циклические ссылки могут вызвать проблемы при сериализации объекта Существуют способы обработки этой проблемы в веб-API (см. раздел "Обработка циклических ссылок на объекты"). но использование DTO просто избегает проблемы в целом.
В шаблоне SPA DTOs содержатся те же данные, что и модели домена. Однако они по-прежнему полезны, так как избегают циклических ссылок из свойств навигации и демонстрируют общую модель DTO.
AccountModels.cs
Этот файл содержит модели членства на сайте. Класс UserProfile определяет схему профилей пользователей в базе данных членства. (В этом случае единственная информация — это идентификатор пользователя и имя пользователя.) Другие классы моделей в этом файле используются для создания форм регистрации пользователей и входа.
Entity Framework
Шаблон SPA использует EF Code First. При разработке code First вы определяете модели в коде, а затем EF использует модель для создания базы данных. EF также можно использовать с существующей базой данных (Database First).
Класс TodoItemContext в папке Models является производным от DbContext. Этот класс обеспечивает связь между моделями и EF.
TodoItemContext содержит коллекцию ToDoItem и коллекцию TodoList. Чтобы запросить базу данных, просто напишите запрос LINQ к этим коллекциям. Например, вот как выбрать все списки to-do для пользователя "Алиса":
TodoItemContext db = new TodoItemContext();
IEnumerable<TodoList> lists =
from td in db.TodoLists where td.UserId == "Alice" select td;
Вы также можете добавлять новые элементы в коллекцию, обновлять элементы или удалять элементы из коллекции и сохранять изменения в базе данных.
контроллеры веб-API ASP.NET
В ASP.NET веб-API контроллеры — это объекты, обрабатывающие HTTP-запросы. Как упоминалось, шаблон SPA использует веб-API для выполнения операций CRUD над экземплярами ToDoList и ToDoItem. Контроллеры находятся в папке контроллеров решения.
-
TodoController: обрабатывает HTTP-запросы для элементов to-do -
TodoListController: обрабатывает HTTP-запросы для списков to-do.
Эти имена являются важными, так как Web API сопоставляет путь URI с именем контроллера. (Чтобы узнать, как веб-API направляет HTTP-запросы к контроллерам, см. статью "Маршрутизация" в ASP.NET веб-API.)
Давайте рассмотрим ToDoListController класс. Он содержит один элемент данных:
private TodoItemContext db = new TodoItemContext();
TodoItemContext используется для взаимодействия с EF, как описано ранее. Методы контроллера реализуют операции CRUD. Веб-API сопоставляет HTTP-запросы от клиента к методам контроллера следующим образом:
| HTTP-запрос | Метод контроллера | Описание |
|---|---|---|
| GET /api/todo | GetTodoLists |
Возвращает коллекцию списков дел. |
| GET /api/todo/id | GetTodoList |
Возвращает список to-do по идентификатору |
| PUT /api/todo/id | PutTodoList |
Обновляет список дел. |
| POST /api/todo | PostTodoList |
Создает новый список to-do. |
| DELETE /api/todo/id | DeleteTodoList |
Удаляет список TODO. |
Обратите внимание, что URI для некоторых операций содержат заполнители для значения идентификатора. Например, чтобы удалить список с идентификатором 42, URI — это /api/todo/42.
Дополнительные сведения об использовании веб-API для операций CRUD см. в статье "Создание веб-API, поддерживающего операции CRUD". Код для этого контроллера довольно простой. Ниже приведены некоторые интересные моменты:
- Метод
GetTodoListsиспользует запрос LINQ для фильтрации результатов по идентификатору пользователя, вошедшего в систему. Таким образом, пользователь видит только данные, принадлежащие ему или ей. Кроме того, обратите внимание, что инструкция Select используется для преобразованияToDoListэкземпляров вTodoListDtoэкземпляры. - Методы PUT и POST проверяют состояние модели перед изменением базы данных. Если ModelState.IsValid имеет значение false, эти методы возвращают HTTP 400, bad request. Дополнительные сведения о проверке модели в веб-API см. в разделе "Проверка модели".
- Класс контроллера также украшен атрибутом [Авторизовать] . Этот атрибут проверяет подлинность HTTP-запроса. Если запрос не прошел проверку подлинности, клиент получает протокол HTTP 401, несанкционированный. Читайте подробнее об аутентификации в статье Аутентификация и авторизация в ASP.NET Web API.
Класс TodoController очень похож на TodoListController. Самое большое различие заключается в том, что он не определяет какие-либо методы GET, так как клиент получит задачи вместе с каждым списком задач.
Контроллеры и представления MVC
Контроллеры MVC также находятся в папке контроллеров решения.
HomeController отрисовывает основной HTML-код для приложения. Представление контроллера Home определено в Views/Home/Index.cshtml. Представление "Главная" отображает разные содержимое в зависимости от того, вошел ли пользователь:
@if (@User.Identity.IsAuthenticated)
{
// ....
}
Когда пользователи вошли в систему, они видят основной пользовательский интерфейс. В противном случае они видят панель входа. Обратите внимание, что эта условная отрисовка выполняется на стороне сервера. Никогда не пытайтесь скрыть конфиденциальное содержимое на стороне клиента— все, что вы отправляете в ответе HTTP, отображается кому-то, кто просматривает необработанные HTTP-сообщения.
Client-Side JavaScript и Knockout.js
Теперь давайте перейдем с серверной стороны приложения на клиент. Шаблон SPA использует сочетание jQuery и Knockout.js для создания гладкого интерактивного пользовательского интерфейса. Knockout.js — это библиотека JavaScript, которая упрощает привязку HTML к данным. Knockout.js использует шаблон с именем Model-View-ViewModel.
- Модель — это данные домена (списки toDo и элементы ToDo).
- Представление — это HTML-документ.
- Модель представления — это объект JavaScript, содержащий данные модели. Модель представления — это абстракция кода пользовательского интерфейса. У него нет знаний о представлении HTML. Вместо этого он представляет абстрактные функции представления, такие как "список элементов ToDo".
Представление привязано к модели представления. Обновления модели представления автоматически отражаются в представлении. Привязки также могут работать в обратном направлении. События в DOM (например, щелчки) привязаны к данным в модели представления, которая активирует вызовы AJAX.
Шаблон SPA упорядочивает клиентский JavaScript на три уровня:
- todo.datacontext.js: отправляет запросы AJAX.
- todo.model.js: определяет модели.
- todo.viewmodel.js: определяет модель представления.
Эти файлы скриптов находятся в папке scripts/app решения.
todo.datacontext обрабатывает все вызовы AJAX к контроллерам веб-API. (Вызовы AJAX для входа определены в другом месте в ajaxlogin.js.)
todo.model.js определяет клиентские модели (браузер) для списков to-do. Существует два класса модели: todoItem и todoList.
Многие свойства в классах модели имеют тип ko.observable. Наблюдаемые - это то, как Knockout творит чудеса. Из документации по Knockout: наблюдаемый — это объект JavaScript, который может уведомлять подписчиков об изменениях. Когда значение наблюдаемого изменяется, Knockout обновляет все HTML-элементы, привязанные к этим наблюдаемым. Например, todoItem имеет наблюдаемые свойства title и isDone:
self.title = ko.observable(data.title);
self.isDone = ko.observable(data.isDone);
Вы также можете подписаться на объект Observable в коде. Например, класс todoItem подписывается на изменения свойств isDone и title:
saveChanges = function () {
return datacontext.saveChangedTodoItem(self);
};
// Auto-save when these properties change
self.isDone.subscribe(saveChanges);
self.title.subscribe(saveChanges);
Просмотр модели
Модель представления определена в todo.viewmodel.js. Модель представления — это центральная точка, в которой приложение привязывает элементы HTML-страницы к данным домена. В шаблоне SPA модель представления содержит наблюдаемый массив todoLists. Следующий код в модели представления сообщает Нокауту применить привязки:
ko.applyBindings(window.todoApp.todoListViewModel);
Привязка данных и HTML
Основной HTML-код страницы задан в Views/Home/Index.cshtml. Так как мы используем привязку данных, HTML -это только шаблон для того, что фактически получает отрисовку. Нокаут использует декларативные привязки. Элементы страницы привязываются к данным путем добавления атрибута data-bind в элемент. Ниже показан очень простой пример, взятый из документации по Knockout:
<p>There are <span data-bind="text: myItems().count"></span> items<p>
В этом примере Knockout обновляет содержимое элемента <span> со значением myItems.count(). Всякий раз, когда это значение изменяется, Knockout обновляет документ.
Нокаут предоставляет ряд различных типов привязки. Ниже приведены некоторые привязки, используемые в шаблоне SPA:
- foreach: позволяет выполнять итерацию по циклу и применять одну разметку к каждому элементу в списке. Используется для отрисовки списков дел и элементов списка дел. В элементе foreach привязки применяются к элементам списка.
- видимый: используется для переключения видимости. Скрыть разметку, если коллекция пуста, или сделать сообщение об ошибке видимым.
- значение: используется для заполнения значений формы.
- щелкните: привязывает событие щелчка к функции в модели представления.
Защита от CSRF
Межсайтовая подделка запроса (CSRF) — это атака, в которой вредоносный сайт отправляет запрос на уязвимый сайт, на котором пользователь уже авторизован. Чтобы предотвратить атаки CSRF, ASP.NET MVC использует маркеры защиты от подделки, также называемые маркерами проверки запросов. Идея заключается в том, что сервер помещает случайный созданный маркер на веб-страницу. Когда клиент отправляет данные на сервер, он должен включать это значение в сообщение запроса.
Маркеры защиты от подделки работают, так как вредоносные страницы не могут считывать маркеры пользователя из-за политики одного источника. (Политики одного источника не позволяют документам, размещенным на двух разных сайтах, получать доступ к содержимому друг друга.)
ASP.NET MVC обеспечивает встроенную поддержку маркеров защиты от подделки с помощью класса AntiForgery и атрибута [ValidateAntiForgeryToken] . В настоящее время эта функция не встроена в веб-API. Однако шаблон SPA включает пользовательскую реализацию для веб-API. Этот код определяется в ValidateHttpAntiForgeryTokenAttribute классе, который находится в папке "Фильтры" решения. Дополнительные сведения о защите от межсайтовых подделок запросов (CSRF) в Web API см. в статье «Предотвращение атак межсайтовых подделок запросов (CSRF)».
Conclusion
Шаблон SPA предназначен для быстрого написания современных интерактивных веб-приложений. Она использует библиотеку Knockout.js для разделения презентации (разметки HTML) от данных и логики приложения. Но Knockout — это не единственная библиотека JavaScript, которую можно использовать для создания SPA. Если вы хотите изучить другие варианты, ознакомьтесь с шаблонами SPA, созданными сообществом.