Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Поскольку с моделями мы закончили, перейдем к наиболее важной части приложения - к контроллеру. Для контроллеров у нас уже имеется папка Controllers. Нажмите на нее правой кнопкой мыши и в появившемся меню выберите Add->Controller.... Перед вами появится диалоговое окно создания нового контроллера. Позже в соответствующей главе мы подробно поговорим о параметрах создания контроллерах да и о самих контроллерах, а пока установите в качестве имени контроллера HomeController и нажмите Add (Добавить)
У вас будет создан следующий контроллер:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace BookStore.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } } }
Контроллер по сути и есть главное звено приложения, которая связывает модель и пользовательский интерфейс. Обратите внимание, что контроллер - это обычный класс, который наследуется от базового класса Controller. Он пока имеет единственный метод Index, который возвращает некоторый результат метода View() - будущее представление. И если мы сейчас запустим приложение, то получим ошибку о том, что представление для данного действия не определено. Но перед тем как добавить представление и приступить к созданию пользовательского интерфейса изменим метод Index следующим образом:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using BookStore.Models; namespace BookStore.Controllers { public class HomeController : Controller { // создаем контекст данных BookContext db = new BookContext(); public ActionResult Index() { // получаем из бд все объекты Book IEnumerable<Book> books = db.Books; // передаем все полученный объекты в динамическое свойство Books в ViewBag ViewBag.Books = books; // возвращаем представление return View(); } } }
Прежде всего, обратите внимание, что, так как у нас модели находятся в другом пространстве имен, хотя и в одном проекте, то мы его должны импортировать. Затем мы создаем контекст данных. Используя свойство Books, мы получаем из базы данных список объектов Book.
Далее мы создаем объект Books в объекте ViewBag и присваиваем ему этот список. Объект ViewBag является таким объектом, который передается в представление. И мы можем определить в этом объекте любую переменную и передать ей некоторое значение, а затем в представлении извлечь это значение.
А теперь создадим само представление. Наведем курсор на метод Index и нажмем правой кнопкой мыши. Нам отобразится меню, в котором выберем Add View....
Затем нам откроется окно добавления представления, где нам будет предложено выбрать имя представления и еще ряд параметров. Поскольку у нас еще нет мастер-страниц в проекте, снимем галочку с флажка Use a layout or masterpage: и нажмем Add.
Позже в соответствующей главе мы подробнее поговорим про опции создания и вообще про представления. А пока Visual Studio автоматически откроет созданное представление Index.cshtml. По сути оно пусто и содержит минимальный код разметки на языке html. Изменим его следующим образом:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Книжный магазин</title> </head> <body> <div> <h3>Распродажа книг</h3> <table> <tr><td><p>Название книги</p></td> <td><p>Автор</p></td> <td><p>Цена</p></td><td></td> </tr> @foreach (var b in ViewBag.Books) { <tr> <td><p>@b.Name</p></td> <td><p>@b.Author</p></td> <td><p>@b.Price</p></td> <td><p><a href="/Home/Buy/@b.Id">Купить</a></p></td> </tr> } </table> </div> </body> </html>
Здесь мы создаем таблицу, в которой будут располагаться наши данные о книгах. Особый интерес представляет конструкция
@foreach (var c in ViewBag.Books)
. Эта конструкция использует синтаксис движка представления Razor (а именно его мы выбрали при создании представления).
Подробнее мы погорим о движке Razor в отдельной главе, а пока вам надо знать, что после символа @
согласно синтаксису мы можем использовать
выражения кода на языке C#.
В цикле мы пробегаемся по элементам в объекте ViewBag.Books, который мы ранее создали в методе контроллера. И затем получаем свойства каждого элемента и помещаем его в ячейку таблицы.
Ссылка в конце - <a href="/Home/Buy/@b.Id">Купить</a>
будет означать адрес,
по которому будет размещаться форма оформления покупки выбранной книги.
Чтобы вызвать контроллер HomeController или отправить ему запрос, нам надо указать в строке запроса его имя - Home. Кроме того,
после имени контроллера нам надо через слеш указать действие или метод контроллера, к которому отправляется запрос. По умолчанию при запуске проекта
или при обращении к сайту система mvc будет вызывать действие Index контроллера HomeController, если мы не укажем иной маршрут по умолчанию в параметрах маршрутизации.
Путь /Home/Buy/@b.Id
означает, что мы будем обращаться к методу Buy контроллера HomeController. Но перед тем как создать этот метод,
наполним приложение данными.
Мы можем уже сейчас запустить наше приложение, однако кроме строки с заголовками в таблице мы ничего не увидим, потому что у нас же еще нет данных. Здесь мы могли поступить двумя способами: либо добавить в базу данных mssql некоторые данные, либо инициализировать начальные данные для моделей в коде. Выберем второй вариант. Для этого в папку Models добавим новый класс BookDbInitializer и добавим в него следующий код:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; namespace BookStore.Models { public class BookDbInitializer : DropCreateDatabaseAlways<BookContext> { protected override void Seed(BookContext db) { db.Books.Add(new Book { Name = "Война и мир", Author = "Л. Толстой", Price = 220 }); db.Books.Add(new Book { Name = "Отцы и дети", Author = "И. Тургенев", Price = 180 }); db.Books.Add(new Book { Name = "Чайка", Author = "А. Чехов", Price = 150 }); base.Seed(db); } } }
С помощью данного класса мы создаем три объекта Book и добавляем их в базу данных. Чтобы этот класс заработал, нам надо не только его объявить, но и запустить. Все начальные настройки и конфигурации у нас хранятся в файле Global.asax. Откроем его и добавим в него в метод Application_Start, который отрабатывает при старте приложения, следующую строчку:
Database.SetInitializer(new BookDbInitializer());
Ну и конечно, импортируем в файле Global.asax пространства имен [имя_проекта].Models и System.Data.Entity, иначе класс BookDbInitializer будет недоступен.
Все, теперь, если мы запустим приложение, то увидим, что в таблице содержатся ранее определенные нами данные:
И если мы откроем папку проекта и зайдем в ней в каталог App_Data, то найдем только что созданную базу данных Bookstore.mdf, которая и будет хранить таблицы с данными.
Да, наша таблица выглядит немного неказисто, не мешало бы применить к ней стили, но не сейчас. Сейчас нам надо создать метод Buy, который будет отвечать за обработку ввода пользователя при оформлении покупки. Добавим в контроллер HomeController следующие два метода:
[HttpGet] public ActionResult Buy(int id) { ViewBag.BookId = id; return View(); } [HttpPost] public string Buy(Purchase purchase) { purchase.Date = DateTime.Now; // добавляем информацию о покупке в базу данных db.Purchases.Add(purchase); // сохраняем в бд все изменения db.SaveChanges(); return "Спасибо," + purchase.Person + ", за покупку!"; }
По сути здесь мы определили одно действие Buy, однако в одном случае оно выполняется при получении запроса GET, а во втором случае -
при получении запроса POST, что мы и определили с помощью атрибутов [HttpGet] и [HttpPost]. Метод public ActionResult Buy(int id)
очень прост - он просто принимает id выбранной книги и возвращает для нее соответствующее представление.
Метод public string Buy(Purchase purchase)
выглядит несколько сложнее. Он принимает переданную ему в запросе POST модель purchase и
добавляет ее в базу данных. В конце мы возвращаем строку сообщения.
И в конце добавим представление Buy. Для этого нажмем на метод public ActionResult Buy(int id)
правой кнопкой и добавим в проект новое представление.
Изменим код нового представления следующим образом:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Покупка</title> </head> <body> <div> <h3>Форма оформления покупки</h3> <form method="post"> <input type="hidden" value="@ViewBag.BookId" name="BookId" /> <table> <tr><td><p>Введите свое имя </p></td> <td><input type="text" name="Person" /> </td></tr> <tr><td><p>Введите адрес :</p></td><td> <input type="text" name="Address" /> </td></tr> <tr><td><input type="submit" value="Отправить" /> </td><td></td></tr> </table> </form> </div> </body> </html>
Здесь мы создали форму ввода данных. При переходе по ссылке "/Home/Buy/2" контроллер будет получать запрос к действию Buy. И так как такой запрос
представляет тип GET, пользователю будет возвращаться форма. После заполнения формы и нажатия на кнопку форма будет оправляться запросом POST,
так как мы его определили в строке <form method="post" action="">
. Контроллер снова будет получать запрос к методу Buy,
только теперь будет выбираться для обработки запроса метод public string Buy(Purchase purchase)
.
Каким образом система MVC угадывает, что мы передали с запросом post информацию о модели? Обратите внимание на поля ввода
<input type="text" name="Person" />
и <input type="text" name="Address" />
. Их свойства name соответствуют
именам свойств модели Purchase. При нажатии кнопки и отправки запроса передаются значения этих полей. Система MVC, используя соглашения по умолчанию,
считает эти значения значениями соответствующих свойств модели.
Теперь первое мини-тренировочное приложение готово, и мы можем его запустить. Перейдите на страницу оформления заказа, заполните поля и нажмите кнопку "Отправить".
После этого ваша заявка на покупку книги попадет в базу данных, а в браузере отобразится соответствующее уведомление.
А теперь добавим к нашему сайту элементы стилизации в виде стилей css, а также мастер-страницы, которые позволяют придать всем страницам сайта единообразный вид.