Controller и Action.
Веб-сайт состоит из страниц. Вообще, веб-сайт состоит не из страниц, а из ответов на запросы, но какую-то определенную структуру мы хотим иметь.
Собственно, у нас есть маршрутизатор, который должен определить, какой метод у какого контроллера вызвать. Поэтому, два основных параметра, которые обязательно должны быть это controller и action. Рассмотрим как задается шаблон маршрутов в App_Start/RouteConfig.cs:
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
Таким образом, url = «/Role/Create/2»
будет означать, что мы находим контроллер RoleController, в этом контроллере находим Create метод, который может принимать (а может и не принимать) параметр id. И если он принимает параметр id, то id = 2 или даже id = “2”, в зависимости, что за тип будет.
Defaults обозначает, что если строка будет “/Role/Create” – то в случае, что Create метод с параметром id и по умолчанию не стоит значение, или не может быть создано default(), то по возможности будет выбран другой метод (мы же полиморфны). Иначе будет сгенерирована ошибка: не найден метод, готовый принять такой запрос.
public ActionResult Index(int? id) { //ok return View(); } … public ActionResult Index(int id = 0) { //ok return View(); } … public ActionResult Index(int id) { //fail return View(); }
В случае url = “/Role” будет вызван метод Index в контроллере RoleController.
В случае url = “/” будет вызван метод Index в контроллере HomeController.
Рассмотрим на примерах.
BaseController
Создадим несколько контроллеров, но для того, чтобы не создавать постоянно доступ к репозиторию, первоначально создадим базовый контроллер BaseController:
public abstract class BaseController : Controller { [Inject] public IRepository Repository { get; set; } }
И
public class HomeController : BaseController { public ActionResult Index() { return View(); } }
View Home/Index.cshtml:
@{ ViewBag.Title = "LessonProject"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>LessonProject</h2> <p> <div class="menu"> <a href="@Url.Action("Index", "Role")">Роли</a> @Html.ActionLink("Пользователи", "Index", "User") </div> </p>
Добавим для просмотра RoleController:
public class RoleController : BaseController { public ActionResult Index() { var roles = Repository.Roles.ToList(); return View(roles); } }
И
@model IList<LessonProject.Model.Role> @{ ViewBag.Title = "Roles"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Roles</h2> <p> @foreach (var role in Model) { <div class="item"> <span class="id"> @role.ID </span> <span class="name"> @role.Name </span> <span class="Code"> @role.Code </span> </div> } </p>
И такой же UserController, собственно, сделаем.
Рассмотрим, как задаются маршруты с помощью Url.Action() и Html.ActionLink().
Url.Action() – принимает параметры, первым – action, потом – controller, потом через new {} – можно задавать и перечислять все остальные.
Html.ActionLink() – формирует тег <a>
, первый параметр – наименование ссылки, второй – action, третий – controller, четвертым(или пятым) параметром идут другие атрибуты тега, если мы хотим добавить другие параметры для маршрутизации – мы должны явно указать пятым параметром null. Т.е.:
@Html.ActionLink(“Пользователь под номером 1”, “Item”, “User”, new {id = 1}, <b>null</b>)
Если не указать null:
@Html.ActionLink(“Пользователь под номером 1”, “Item”, “User”, new {id = 1})
то ссылка будет выглядеть так:
<a href=”/User/Item?length=4”>Пользователь под номером 1</a>
Порядок объявления маршрутов
Создадим маршрут, который будет расположен ранее и относится только к RoleController:
routes.MapRoute( name: "Role", url: "roli/{action}/{id}", defaults: new { controller = "Role", action = "Index", id = UrlParameter.Optional } );
Строка “roli/{action}/{id}” однозначно задает имя контроллера в секции defaults. А action является параметром.
Результат. Ссылка стала:
<a href="/roli">Роли</a>
Уберем из defaults action=”Index”:
<a href="/roli/Index">Роли</a>
Поместим после объявления “Defaults”:
<a href="/Role">Роли</a>
Такая ссылка получилась, потому что вышестоящим правилом маршрута “default” можно задать путь к Role/Index:
context.MapRoute( name : "default", url : "{controller}/{action}/{id}", defaults : new { controller = "Home", action = "Index", id = UrlParameter.Optional }, );
Еще надо рассмотреть один метод, который называется IgnoreRoute
, он указывает маршрутизатору, что если url подходит под шаблон, то нужно вернуть ресурс, который расположен по тому адресу, а не пытаться находить контроллер.
Ограничения (Constrains)
Мы можем добавить в маршрутизацию ограничения запросов браузера, которые соответствуют особому маршруту. Например, id должен быть в нашем случае числовым:
routes.MapRoute( name: "Role", url: "roli/{action}/{id}", defaults: new { controller = "Role", action = "Index", id = UrlParameter.Optional }, constraints : new {id = @"\d+"} );
При передаче id, которое не соответствует данному условию, будет или выбран другой маршрут, или метод не будет найден и ссылка будет битой:
Для:
<a href="@Url.Action("Index", "Role", new { id = "privet" })">Роли</a>
Будет:
<a href="/Role/Index/privet">Роли</a>
А для:
<a href="@Url.Action("Index", "Role", new { id = "1" })">Роли</a>
Будет:
<a href="/roli/Index/1">Роли</a>
Примечание: Более подробно об ограничениях можно узнать тут: http://stephenwalther.com/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints.aspx
Areas
Чтобы разделить различные по свойствам функциональные модули веб-приложения. Например, форум отдельно от всего сайта. Мы же поделим на часть Admin – где будет админка, и всё остальное, которое будет называться Default.
Сделаем следующие действия:
- Переименуем _Default в Default везде.
- Перенесем свои контроллеры (кроме
BaseController
) в папку Areas/Default/Controllers - Переименуем namespace для контроллеров в
LessonProject.Areas.Default.Controllers
- Исправляем
DefaultAreaRegistration
.Здесь важно обратить внимание на новый параметр для задания маршрутов: namespaces, он указывает, из каких namespace можно выбирать контроллеры для разбора маршрута:
public class DefaultAreaRegistration : AreaRegistration { public override string AreaName { get { return "Default"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( name : "default", url : "{controller}/{action}/{id}", defaults : new { controller = "Home", action = "Index", id = UrlParameter.Optional }, namespaces : new [] { "LessonProject.Areas.Default.Controllers" } ); } }
- В Global.asax есть строка
AreaRegistration.RegisterAllAreas();
которая регистрирует все найденные объявления area, но она нам не подходит, так как если DefaultArea зарегистрировать раньше AdminArea, то будет срабатывать маршрутизация Default, а в админку мы уже не сможем попасть, поэтому исправляем:
var adminArea = new AdminAreaRegistration(); var adminAreaContext = new AreaRegistrationContext(adminArea.AreaName, RouteTable.Routes); adminArea.RegisterArea(adminAreaContext); var defaultArea = new DefaultAreaRegistration(); var defaultAreaContext = new AreaRegistrationContext(defaultArea.AreaName, RouteTable.Routes); defaultArea.RegisterArea(defaultAreaContext);
- Регистрацию маршрутов убираем (не api).
Запускаем.
Все исходники находятся по адресу https://bitbucket.org/chernikov/lessons
ссылка на оригинал статьи http://habrahabr.ru/post/176021/
Добавить комментарий