Создание контроллера и представлений

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Так как с моделями и настройкой контекста данных мы закончили, то займемся другим компонентом приложения - контроллером. Для контроллеров предназначена папка Controllers. По умолчанию при создании проекта в нее добавляется контроллер HomeController, который практически не имеет никакой функциональности, и сейчас его код выглядит следующим образом:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace BookStore.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}

В контроллере определены по умолчанию три метода: Index, About и Contact. Нам они не нужны. Изменим код контроллера на следующий:

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();
        }
    }
}

Прежде всего, мы подключаем пространство имен моделей, даже не смотря на то, что он находятся в одном проекте, но в разных пространствах. Затем создается объект контекста данных, через который мы будем взаимодействовать с бд: BookContext db = new BookContext();.

Далее используя свойство db.Books, получаем из базы данных набор объектов Book. Теперь надо передать этот набор в представление.

Для передачи списка объектов Book в представление используем объект ViewBag. ViewBag представляет такой объект, который позволяет определить любую переменную и передать ей некоторое значение, а затем в представлении извлечь это значение. Так, мы определяем переменную ViewBag.Books, которая и будет хранить набор книг.

Теперь создадим само представление для вывода списка книг. Для представлений в проекте предназначена папка Views. По умолчанию в этой папке уже есть подкаталог для представлений контроллера Home, в котором три представления: About.cshtml, Contact.cshtml и Index.chtml.

Первые два представления нам уже не понадобятся, и их можно спокойно удалить. А представление Index.cshtml откроем и изменим следующим образом:

@{
    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>

Самым первым выражением Layout = null; мы указываем, что мастер-страница не будет применяться к этому представлению. Далее мы добавим к нему мастер-страницу и узнаем, зачем она нужна, а пока обойдемся без нее.

Практически весь остальной код представляет собой стандартный код на языке html: создание обычной таблицы, которая выводит информацию о продаваемых книгах. Здесь также используется интересная конструкция @foreach (var b in ViewBag.Books). Эта конструкция применяет синтаксис Razor. Подробнее о движке Razor и его ситаксисе мы поговорим в отдельной главе, а пока вам надо знать, что после символа @ согласно синтаксису мы можем использовать выражения кода на языке C#/VB.NET.

То есть тут мы создаем цикл. В нем мы пробегаемся по всем элементам в объекте ViewBag.Books, который был ранее создан в методе контроллера. И затем получаем значение свойства каждого элемента с помощью синтаксиса Razor: @b.Name и помещаем его в ячейку таблицы.

В последнюю колонку таблицы для каждого элемента добавляется ссылка <a href="/Home/Buy/@b.Id">Купить</a>. При нажатии на эту ссылку методу Buy контроллера HomeController будет отправляться запрос, в котором вместо @b.Id будет указан id книги. Пока у нас, правда, отсутствует метод Buy, но скоро мы его создадим.

Основы маршрутизации

Чтобы обратиться к контроллеру HomeController или отправить ему запрос, нам надо указать в строке запроса его имя - Home. Кроме того, после имени контроллера нам надо через слеш указать действие или метод контроллера, к которому отправляется запрос. По умолчанию при запуске проекта или при обращении к сайту система mvc будет вызывать действие Index контроллера HomeController, если мы не укажем иной маршрут по умолчанию в параметрах маршрутизации. Путь /Home/Buy означает, что мы будем обращаться к методу Buy контроллера HomeController. А добавление в запрос параметра /Home/Buy/@b.Id, означает, что такой метод может принимать параметр. Но перед тем как создать этот метод, наполним приложение данными.

Данные для моделей по умолчанию

Так как мы будем использовать подход Code First, то нам не надо вручную создавать базу данных и наполнять ее данными. Мы можем воспользоваться специальным классом, который за нас добавит начальные данные в бд. Для этого в папку 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);
        }
    }
}

Класс DropCreateDatabaseAlways позволяет при каждом новом запуске заполнять базу данных заново некоторыми начальными данными. В качестве таких начальных значений здесь создаются три объекта Book. Используя метод db.Books.Add мы добавляем каждый такой объект в базу данных.

Однако чтобы этот класс действительно сработал, и заполнение базы данных произошло, нам надо запустить его при запуске приложения. Все начальные настройки приложения и конфигурации находятся в файле Global.asax. Откроем его и добавим в метод Application_Start, который отрабатывает при старте приложения, следующую строку Database.SetInitializer(new BookDbInitializer());:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using BookStore.Models;
using System.Data.Entity;

namespace BookStore
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            Database.SetInitializer(new BookDbInitializer());
			
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

И, наконец, мы можем запустить проект на выполнение и увидеть на веб-странице в браузере наши данные по умолчанию:

И если мы откроем папку проекта на жестком диске и в этой папке перейдем к каталогу 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] мы можем указать, какой метод какой тип запроса обрабатывает.

Так как предполагается, что в метод Buy будет передаваться id книги, которую пользователь хочет купить, то нам надо определить в методе соответствующий параметр: public ActionResult Buy(int id). Затем этот параметр передается через объект ViewBag в представление, которое мы сейчас создадим.

Метод public string Buy(Purchase purchase) выглядит несколько сложнее. Он принимает переданную ему в запросе POST модель purchase и добавляет ее в базу данных. Результатом работы метода будет строка, которую увидит пользователь.

А весь код по добавлению нового объекта в бд благодаря использованию EntityFramework фактически сводится к двум строчкам:

db.Purchases.Add(purchase);
db.SaveChanges();

И в конце добавим представление Buy.cshtml. Для этого нажмем на метод public ActionResult Buy(int id) правой кнопкой и в появившемся списке выберем Add View...(Добавить представление). Перед нами откроется окно добавления нового представления:

Оставим все установки по умолчанию, только снимем галочку с поля Use a layout page, так как пока мастер-страницу мы не будем использовать. И нажмем Add (Добавить). Изменим код нового представления следующим образом:

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Покупка</title>
</head>
<body>
    <div>
        <h3>Форма оформления покупки</h3>
        <form method="post" action="">
            <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, передавая ему в качестве параметра id значение 2. И так как такой запрос представляет тип GET, пользователю будет возвращаться данное представление с формой.

Представление по сути представляет собой форму для ввода данных. Обратите внимание, что так как нам не надо изменять значение BookId, однако это значение все равно нам нужно для формирования модели Purchase, то мы его вкладываем в скрытое поле в начале формы.

После заполнения формы и нажатия на кнопку форма будет оправляться запросом POST, так как мы его определили в строке <form method="post" action="">. Контроллер снова будет получать запрос к методу Buy, только теперь будет выбираться для обработки запроса метод public string Buy(Purchase purchase).

Как система MVC угадывает, что мы передали с запросом post информацию о модели Purchase, а не набор разрозненных значений полей формы? Обратите внимание на поля ввода <input type="text" name="Person" /> и <input type="text" name="Address" />. Значение их атрибута name соответствуют именам свойств модели Purchase. После нажатия кнопки и отправки запроса приложение получает значения этих полей. Система MVC, используя соглашения по умолчанию, считает эти значения значениями соответствующих свойств модели и проводит связывание отдельных значений со свойствами модели.

Теперь запустим наше приложение. На главной странице выберем какую-нибудь книгу и нажмем на ссылку "Купить". На форме заполним поля и нажмем кнопку "Отправить".

После нажатия кнопки информация о покупке попадет в базу данных, а в браузер отобразит уведомление:

На этом небольшое мини-тренировочное приложение готово. Теперь сделаем приложение красивее, добавив стилизацию. А также добавим поддержку мастер-страниц.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850