Создание базовой области
Давайте начнем с создания области и рассмотрения того, как это работает. Нажмите правой кнопкой мыши на проекте Product Catalog в Solution Explorer и выберите Add > Area, как это продемонстрировано на рисунке 13-1.
Рисунок 13-1: Пункт контекстного меню Add Area.

Выбор пункта меню Area предоставляет диалоговое окно Add Area, где нам необходимо заполнить поле Area Name, как это продемонстрировано на рисунке 13-2.
Рисунок 13-2: Диалоговое окно Add Area.

При создании первой области в MVC проект будет добавлена новая папка верхнего уровня Areas. Внутри этой папки Areas каждая область располагается в своей собственной папке, и в каждой папке Area вы найдете папки для контроллеров, моделей и представлений, специфичные для этой области. Наконец, мастер Add Area также добавляет класс регистрации области.
В проект, продемонстрированный на рисунке 13-3, входят три области для администрирования, каталога товаров и информации об аккаунте.
Рисунок 13-3: Проект с тремя отдельными областями.

Мастер Add Area входит в комплект установщика ASP.NET MVC, но вы не обязаны использовать его. Мастер создает корректную структуру папок и класс регистрации области, но если инструмент по каким-то причинам был бы недоступен, вам просто нужно было бы следовать тому же самому соглашению о структуре папок.
Помимо структуры папок, мастер создает важный класс регистрации области. Класс содержит информацию, которая описывает для области название и маршрутизацию, а также позволяет изменять используемую по умолчанию информацию о регистрации области. Если бы вы использовали мастер, то ваш класс регистрации области выглядел бы как-то так:
Листинг 13-1: Класс регистрации области, используемый по умолчанию
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute("Admin_default",
"Admin/{controller}/{action}/{id}",
new
{
controller = "Profile",
action = "Index",
id = UrlParameter.Optional
}
);
}
}
Строка 1: Наследуется от
AreaRegistration
Строка 3: Задает имя области
Строка 11: Принимает
AreaRegistrationContext
Строка 13-20: Создает маршрут для области
Класс AdminAreaRegistration
содержит информацию о регистрации области и наследуется от MVC класса AreaRegistration
. AreaRegistration
– это абстрактный класс с одним абстрактным свойством, AreaName
, и одним абстрактным методом, RegisterArea
. Свойство AreaName
используется в дальнейшем для целей маршрутизации. Метод RegisterArea
принимает единственный объект AreaRegistrationContext
, содержащий свойства и методы, которые вы можете использовать для описания области. В общем, для описания роутов, которые должна использовать эта область, вы можете просто воспользоваться методом MapRoute
. В примере листинга 13-1 все URL роута, начинающиеся с "Admin", будут направлять к контроллерам в области Admin
.
AreaRegistrationContext
позволяет нам конструировать роуты, а также конфигурировать пространство имен нашей области. По умолчанию свойство роута Namespaces
будет содержать пространство имен, в котором расположен класс AdminAreaRegistration
. Каждое из добавленных пространств имен будет использоваться для регистрации глобальных роутов таким образом, чтобы контроллеры в пространстве имен конкретной области корректно выбирались движком маршрутизации. Если мы решим разорвать условности и разместить наши контроллеры в пространстве имен, которое не расположено в том же самом базовом пространстве имен, что и наш тип AdminAreaRegistration
, то нам необходимо будет добавить эти пространства имен в AreaRegistrationContext
.
После того как мы создали наши классы AreaRegistration
, мы должны убедиться в том, что наши области регистрируются при запуске приложения. В проектах, созданных с помощью используемого по умолчанию ASP.NET MVC шаблона, уже будет присутствовать код регистрации. Если мы перемещаем существующий MVC 1 проект, то нам придется добавить следующий код метода Application_Start
. Для MVC 2.0 никаких перемещений не требуется.
Листинг 13-2: Метод запуска приложения с регистрацией роута и области
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
Метод AreaRegistration.RegisterAllAreas
сканирует комплекты в папке bin
приложения на факт присутствия типов, заимствованных от класса AreaRegistration
, которые обладают конструктором без аргументов.
После того как мы разместили регистрацию нашей области, мы можем добавлять контроллеры, модели и представления в папки нашей области. В данном примере мы получим экраны администрирования, связанные с профилем текущего пользователя. Один из этих экранов будет контролироваться контроллером под названием ProfileController
. Поскольку этот контроллер может быть связан с другими экранами администрирования, мы поместим этот контроллер и его представления в папку Admin
, как это показано на рисунке 13-4.
Рисунок 13-4: ProfileController
и представления в папке Admin area.

В наш ProfileController
входят три действия: Edit
, Index
и Show
. Каждое представление этого контроллера располагается в папке конкретного контроллера, папке Profile
. В данный момент система анализа представлений сначала выполняет поиск папки конкретной области, затем переходит в папку Shared
конкретной области, а потом в глобальную папку Shared
. Частичные представления, макеты и файлы запуска представлений конкретной области могут помещаться в папку области Shared
для того, чтобы они быди видимы только для этой конкретной области. В таком случае мы можем создать глобальный макет, который содержит только общий сквозной шаблон. В каждую область тогда входил бы макет конкретной области, который использовался бы представлениями только в данной области. Если наши экраны администрирования пользуются одним и тем же универсальным макетом, то мы можем использовать макет только для наших экранов администрирования.
Для действий индивидуального контроллера не требуется задавать имя области при выборе представлений. В следующем листинге действие Index
выбирает представление Index
, оставляя при этом имя представления не заданным.
Листинг 13-3: ДействиеIndex
вProfileController
public virtual ActionResult Index()
{
var profiles = _profileRepository.GetAll();
return View(profiles);
}
Контроллерам в пространстве имен конкретной области (например, AreasExample.Areas.Admin
) присваивается специальная метка данных роута: area
. Это значение данных роута берется из имени области, указанной в регистрации области. При поиске представлений движок представлений использует это значение метки area
для того, чтобы искать папки с этим именем области.
Внутри наших представлений нам не нужно задавать значение области данных роута при генерации ссылок на другие действия контроллера внутри этой области. Ниже приведена ссылка на экране Edit
, которая отправляет нас обратно к списку профилей:
Листинг 13-4: Связывание с действием в пределах того же самого контроллера и области
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Нам нужно только подставить название действия, поскольку названия контроллера и области будут заимствованы из данных роута текущего запроса. Если мы захотим дать ссылку на внешнюю область, то нам нужно будет явно подставить эти данные роута. На рисунке 13-5 страница Edit
профиля содержит пункты меню, а также виджет авторизации.
Рисунок 13-5: Скриншот страницы Edit
профиля со ссылками на внешние области.

Действие Edit
расположено в ProfileController
, который в свою очередь, располагается в области Admin
. На рисунке 13-5 пункты меню Home и About направляют обратно в корневую область (или в область по умолчанию). Помимо этого ссылки Log Off
и Profile
направляют к корневой области и области Admin
соответственно. Но эти пункты отображаются на страницах в рамках всего сайта, а не только внутри области Admin
.
Представление Edit
наследуется из глобального макета.
Листинг 13-5: Представление Edit
, указывающее на глобальный макет
@model EditProfileInput
@{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
В наш глобальный макет мы включаем ссылки на контроллер Profile
, а также на виджет авторизации, который ссылается на многочисленные области. В представлении Edit
нам не нужно было указывать область, когда мы ссылались обратно на действие Index
ProfileController
, потому что это действие логически все еще находилось в том же контроллере и области, что и представление Edit
, но нам нужно было сделать глобальные ссылки и виджеты эластичными и независимыми от областей. Если бы мы не указали название области для ссылки Log Off, то она не отображала бы корректно запрос в области Admin
. Сгенерированный URL содержал бы некорректную информацию об области, как это продемонстрировано на рисунке 13-6.
Рисунок 13-6: Некорректно сгенерированный URL, содержащий дополнительные параметры области.

Наш AccountController
располагается в корневой папке Controller
, но URL был сгенерирован так, будто он расположен в области Admin
. При генерации URL в глобальном контенте, который используется совместно различными областями, и при проставлении ссылок на различные области нам необходимо включать информацию о роуте области.
В следующем листинге наше меню содержит данные роута области для того, чтобы убедиться в том, что меню корректно связывается независимо от того, мастер-страница какой области используется.
Листинг 13-6: menu HTML
, содержащий информацию о роуте области
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home",
new { area = null }, null)
</li>
<li>@Html.ActionLink("Profiles", "Index", "Profile",
new { area = "Admin" }, null)
</li>
<li>@Html.ActionLink("About", "About", "Home",
new { area = null }, null)
</li>
</ul>
В каждом методе ActionLink
листинга 13-6 мы задаем дополнительную область данных роута для ссылки. Ссылки Home и About находятся в корневой папке Controllers
, поэтому мы оставляем название области незаполненным. Ссылка Profile направляет на область Admin
, поэтому нам необходимо задать значение роута area
– Admin
. Значение роута "area" должно корректно сопоставляться с AreaName
. Нам также нужно изменить совместно используемое частичное представление авторизации, поскольку это частичное представление используется в рамках всех областей.
Теперь ссылки будут явно задавать области, как это показано ниже.
Листинг 13-7: Наше частичное представление авторизации, в которое входит информация об области
@if (Request.IsAuthenticated)
{
<text>Welcome <b>@Context.User.Identity.Name</b>!
[ @Html.ActionLink("Log Off", "LogOff", "Account"
, new { area = "" }, null)
|
@(Html.ActionLink("Profile", "Show", "Profile",
new
{
area = "Admin",
username = Context.User.Identity.Name
}, null))
]
</text>
}
else
{
@:[ @Html.ActionLink("Log On", "LogOn", "Account",
new { area = "" }, null) ]
}
К сожалению, не существует перегрузки ActionLink
, которая позволяла бы нам задавать название области без RouteValueDictionary
. В следующем разделе мы изучим то, как мы можем воспользоваться преимуществами T4MVC проекта для того, чтобы генерировать URL роута в нашем приложении.