Предыдущий ролик Следующий ролик  

Видео урок: Solution: Adding transactions

Основы ASP.NET MVC 5

Сейчас я продемонстрирую вам одно из возможных решений той задачи, которую я поставил перед вами в предыдущем видео. Начну с добавления класса Transaction в папку Models. Я уже вставил сюда несколько свойств, но проанализирую их вместе с вами. Нужно преобразовать это пространство имен в атрибут аннотации данных. Итак, класс Transaction будет обладать свойством ID типа integer, выступающим в качестве первичного ключа, свойством Amount типа decimal и свойством CheckingAccountID, которое будет соответствовать внешнему ключу базы данных, определяющей текущий счет авторизованного пользователя.

Благодаря добавлению этого свойства навигации для соответствующего CheckingAccount, Entity Framework будет знать, что это свойство нужно использовать как внешний ключ. Кроме того, необходимо добавить свойство навигации в файл CheckingAccount.cs. Опять же, используем ключевое слово virtual, включающее режим отложенной загрузки. Это будет ICollection<Transaction>. Назовем его "Transactions". Это свойство позволит нам быстро обращаться ко всем операциям, связанным с данным текущим счетом, скрытно объединяясь с этим внешним ключом.

Затем добавим контроллер TransactionController. Я воспользуюсь шаблоном "Пустой MVC-контроллер", потому что знаю, что пока мне нужно реализовать только операцию внесения средств на счет. Итак, заменим это действие на Deposit, которое будет возвращать представление, демонстрирующее форму с одним текстовым полем для ввода суммы. Теперь построим решение по клавише Ctrl+Shift+B, чтобы при построении представления мы опирались на обновленные данные. После этого можно нажать правую кнопку мыши и выбрать пункт "Добавить представление".

Выберу шаблон "Create", чтобы сгенерировалась форма. В качестве класса модели укажу Transaction, а для класса контекста данных - ApplicationDbContext. Класс контекста данных задавать необязательно, но указанный класс добавит необходимый класс DbSet для операций в случае его отсутствия в приложении. После добавления представления мы бегло просмотрим этот класс в файле IdentityModels.cs. Удалим эти полные пространства имен, чтобы сделать код более читабельным.

В форме внесения средств нам точно не понадобится CheckingAccountID, поскольку мы сможем найти его по авторизованному пользователю. Поэтому я удалю весь этот раздел с надписями и полями для идентификатора текущего счета. Вернемся к TransactionController и создадим еще одно действие, позволяющее управлять отправкой формы. Для этого действия необходим атрибут HttpPost, а в качестве параметра оно будет принимать экземпляр класса Transaction.

И конечно, опять же, мне нужно указать пространство имен модели. Затем добавим приватный ApplicationDbContext, который можно использовать в любом методе данного контроллера. После этого мы просто добавляем элемент transaction в свойство Transactions класса DbSet и вызываем метод SaveChanges. Вместо того чтобы снова возвращаться к представлению Deposit, мы перенаправим пользователя на главную страницу приложения. Компонент JQuery validation позаботится о проблемах, связанных с вводом пользователями некорректных сумм, но только если происходит что-то забавное, неплохо бы проверить валидность модели и на стороне сервера.

Сделать это можно посредством добавления проверки: if(ModelState.IsValid). Если модель не валидна, то в представлении Deposit будут отображаться сообщения об ошибках валидации. Если вы внимательно следили за моими действиями, то поймете, что этот код пока не работает, поскольку мы еще нигде не задали значение свойства CheckingAccountID класса Transaction. Один из способов задания значения этого свойства - добавить куда-нибудь на форму внесения средств скрытые поля, например, с помощью кода Razor и HTML.Hidden, а затем передать CheckingAccountID с помощью ViewModel или ViewBag.

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

Не забывайте, что в представлении Index из папки Home есть ссылка на представление Deposit. Поэтому давайте создадим URL и добавим параметр строки запроса с помощью Url.Action. Это будет URL для представления Deposit из TransactionController. Мы передадим значение строки запроса с помощью CheckingAccountID, который уже есть в ViewBag.

Наконец, в действии Index класса HomeController можно создать переменную userId для авторизованного пользователя. Не забудьте, что я давал вам подсказку - использовать пространство имен Microsoft.Asp.Net.Identity, для того чтобы этот метод расширения заработал. И перед тем как я попытаюсь найти checkingAccountId с помощью этого userId, позвольте мне объявить здесь свойство DbContext, опять указав пространство имен модели.

После этого вытащим checkingAccountId из базы данных текущих счетов с помощью метода расширения Where, выполнив фильтрацию по ApplicationUserId и взяв только самый первый результат. Наконец, добавим этот результат в ViewBag, чтобы ссылка на страницу внесения средств сформировалась должным образом. Поскольку мы полагаемся на тот факт, что выполнять эту операцию смогут только авторизованные пользователи, неплохо было бы добавить фильтр авторизации над методом Index.

Это вынудит пользователей сначала пройти процедуру авторизации. Кроме того, следует добавить атрибут Authorized и в наш TransactionController. Мы никогда не позволим гостям приложения выполнять какие-либо операции. Перед тем как все это протестировать, давайте с помощью консоли диспетчера пакетов обновим базу данных, чтобы создать таблицу операций. Как видите, она применила только автоматическую миграцию, поэтому теперь я могу построить решение и запустить приложение по клавише Ctrl+F5.

Поскольку я уже вошел в систему, я вижу главную страницу приложения, а также могу видеть параметр строки запроса для URL кнопки Deposit. Если открыть исходный код страницы, то можно увидеть, что в действии form тоже есть параметр строки запроса checkingAccountId. Во время отправки формы среда выполнения совершит ловкий трюк, сформировав модель операции с помощью поля формы Amount (Сумма) и этого параметра строки запроса. Итак, давайте протестируем эту форму прямо сейчас.

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