ASP NET.MVC Урок 4. Routing и Bundles

от автора

Цель урока: Изучить инициализацию маршрутизации. Деление на Areas в приложении. Принципы создания маршрутизации.

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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *