Области

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

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

ASP.NET Core MVC позволяет организовать приложение в виде областей, где каждая область представляет какой-то свой сегмент приложения. Например, одна область может отвечать за функции администрирования, другая - за управление учетными записями и т.д. И каждая область представляет собой мини-проект, имеет свою собственную структуру каталогов. Это позволяет разрабатывать и тестировать код для каждой области отдельно независимо от других областей.

Возьмем простой проект ASP.NET Core с MVC и добавим в него области. Как правило, области помещаются в отдельную папку. Поэтому добавим в проект новую папку, которую назовем Areas. Затем в эту папку добавим каталог под названием Store. То есть у нас будет область под названием Store.

И далее в папке Areas/Store создадим подкаталоги Controllers и Views. В итоге проект будет выглядеть так:

Области в ASP.NET Core

Затем в папку Controllers добавим новый контроллер HomeController:

using Microsoft.AspNetCore.Mvc;

namespace AreasApp.Areas.Store.Controllers
{
    [Area("Store")]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

Для ассоциации контроллера с определенной областью к этому контроллеру применяется атрибут Area, в который передается название области. Без этого атрибута контроллер не будет принадлежать области Store.

Далее в папку Areas/Store/Views добавим подкаталог Home - для представлений нового контроллера. И затем в этот подкаталог поместим представление Index.cshtml с одной строкой:

<h2>HomeController из области Store</h2>

Вообще поиск представления для контроллера из области ведется по следующим путям:

  • /Areas/Store/Views/Home/

  • /Areas/Store/Views/Shared/

  • /Views/Shared/

Соответственно все три выше указанные папки мы могли бы использовать для хранения представления Index.cshtml для контроллера из области Store.

Таким образом, проект теперь выглядит так:

Добавление областей в ASP.NET Core MVC

Но пока эта область совершенно неактивна. Мы никак не можем к ней обратиться. И теперь добавим в приложение поддержку этой области. Для этого изменим класс Startup:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace AreasApp
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();
			
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "MyArea",
                  pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Для сопоставления с областью в первом маршруте определен сегмент area. Ограничение exists используется для того, чтобы маршрут сопоставлялся только с теми областями, которые определены в приложении.

И теперь мы сможем обращаться к области с запросом http://localhost:xxxx/Store:

Areas in ASP.NET Core

В данном случае определяется маршрут для всех областей. С помощью метода MapAreaControllerRoute() можно указать маршрут для конкретной области:

public void Configure(IApplicationBuilder app)
{
	app.UseDeveloperExceptionPage();
	app.UseStaticFiles();

	app.UseRouting();

	app.UseEndpoints(endpoints =>
	{
		// маршрут для области store
		endpoints.MapAreaControllerRoute(
			name: "store_area",
			areaName:"store",
			pattern: "store/{controller=Home}/{action=Index}/{id?}");

		endpoints.MapControllerRoute(
			name: "default",
			pattern: "{controller=Home}/{action=Index}/{id?}");
	});
}

Метод MapAreaControllerRoute() принимает три обязательных параметра: имя маршрута, имя области (areaName) и шаблон маршрута. Причем шаблон маршрута начинается с названия области: "store/{controller=Home}/{action=Index}/{id?}"

Подобным образом можно определить маршруты для нескольких областей:

app.UseEndpoints(endpoints =>
{
	// маршрут для области store
	endpoints.MapAreaControllerRoute(
		name: "store_area",
		areaName:"store",
		pattern: "store/{controller=Home}/{action=Index}/{id?}");
		
	// маршрут для области service
	endpoints.MapAreaControllerRoute(
		name: "service_area",
		areaName:"service",
		pattern: "service/{controller=Home}/{action=Index}/{id?}");

	endpoints.MapControllerRoute(
		name: "default",
		pattern: "{controller=Home}/{action=Index}/{id?}");
});

Несмотря на то, что в примере выше шаблон маршрута начинается с названия области и при обращении к методу контроллеру мы вводим в начале название области, в принципе это необязательно. Например, определим следующий маршрут:

app.UseEndpoints(endpoints =>
{
	// маршрут для области store
	endpoints.MapAreaControllerRoute(
		name: "store_area",
		areaName:"store",
		pattern: "products/{controller=Home}/{action=Index}/{id?}");

	endpoints.MapControllerRoute(
		name: "default",
		pattern: "{controller=Home}/{action=Index}/{id?}");
});

Теперь шаблон маршрута для области Store начинается с токена "products", однако параметр areaName по прежнему позволяет связать данный маршрут с областью Store. Только теперь в адресной строке нам придется вводить вначале "Products", а не "Store":

Настройка маршрутизации области и MapAreaControllerRoute

Определение областей через RouterMiddleware и UseMvc

Подобным образом мы можем использовать области при маршрутизациии через RouterMiddleware и метод UseMvc:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace AreasApp
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews(op => op.EnableEndpointRouting = false);
        }
        
        public void Configure(IApplicationBuilder app)
        {
			app.UseStaticFiles();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "areas",
                    template: "{area:exists}/{controller=Home}/{action=Index}");
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Определение маршрутов для конкретных областей:

app.UseMvc(routes =>
{
	routes.MapAreaRoute(
		name: "store_area",
		areaName:"Store",
		template: "Products/{controller=Home}/{action=Index}/{id?}");
	routes.MapRoute(
		name: "default",
		template: "{controller=Home}/{action=Index}/{id?}");
});

Настройка маршрутизации через атрибуты

Также мы могли бы задать маршрут через атрибут маршрутизации, в котором параметр area представлял бы область:

[Area("Store")]
public class HomeController : Controller
{
    [Route("[area]")]
	[Route("[area]/[controller]")]
	[Route("[area]/[controller]/[action]")]
    public IActionResult Index()
    {
        return View();
    }
}

Для обращения к такому методу Index мы можем использовать три адреса: http://localhost:xxxx/Store, http://localhost:xxxx/Store/Home и http://localhost:xxxx/Store/Home/Index

В этом случае в классе Startup можно не определять маршрут для области:

app.UseEndpoints(endpoints =>
{
	endpoints.MapControllerRoute(
		name: "default",
		pattern: "{controller=Home}/{action=Index}/{id?}");
});

Также можно использовать префиксы:

[Area("Store")]
public class HomeController : Controller
{
    [Route("Products")]
	[Route("Products/[controller]")]
	[Route("Products/[controller]/[action]")]
    public IActionResult Index()
    {
        return View();
    }
}

Для обращения к такому методу Index мы можем использовать следующие адреса: http://localhost:xxxx/Products, http://localhost:xxxx/Products/Home и http://localhost:xxxx/Products/Home/Index

Работа с областями

При работе с областями следует учитывать ряд моментов.

Если в контроллеры области используют представления, то система будет искать эти представления по следующим путям:

/Areas/Название_области/Views/Название_контроллера/Имя_представления.cshtml
/Areas/Название_области/Views/Shared/Имя_представления.cshtml
/Views/Shared/Имя_представления.cshtml

Поэтому все представления, которые находятся вне описанных выше путей, будут недоступны для области. К примеру, в главном проекте функциональность tag-хелперов добавляется с помощью файла _ViewImports.cshtml. В области он будет недоступен. И чтобы задействовать tag-хелперы в представлениях в области, нам надо добавить аналогичный файл в каталог Views, который находится в области. Либо же добавлять в представления области эту строку, где надо использовать tag-хелперы.

Другой важный момент - это генерация ссылок. При генерации ссылок в представлениях отдельных областей используются все те хелперы, например, Html.ActionLink или AncorTagHelper, однако тут есть и некоторые особенности.

Чтобы сгенерировать ссылку на какое-либо действие контроллера, которые находятся внутри области, то мы указываем действие и контроллер (если действие находится в другом контроллере):

@Html.ActionLink("Онлайн-магазин", "Index", "Home")
// или
<a asp-action="Index" asp-controller="Home">Онлайн-магазин</a>

В итоге будет сгенерирована ссылка: <a href="Store/Home/Index/">Онлайн-магазин</a> (если текущее представление расположено в области Store).

Если же требуемое действие и контроллер находятся в другой области, то мы указываем область в параметре хелпера:

@Html.ActionLink("Все книги", "List", new { area = "Store", controller = "Book" })
// или
<a asp-action="List" asp-controller="Book" asp-route-area="Store">Все книги</a>

Сгенерированная ссылка будет выглядеть так: <a href="Store/Book/List/">Все книги</a>

Если же метод и контроллер, на которые мы хотим сделать ссылку, находятся в основной части приложения, то для параметра area определяем пустую строку:

@Html.ActionLink("Главная", "Index", new { area = "", controller = "Home" })
// или так
<a asp-action="Index" asp-controller="Home" asp-route-area="">Главная</a>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850