Главная страница   /   13.1. Создание базовой области (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

13.1. Создание базовой области

Давайте начнем с создания области и рассмотрения того, как это работает. Нажмите правой кнопкой мыши на проекте 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, поэтому нам необходимо задать значение роута areaAdmin. Значение роута "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 роута в нашем приложении.