区域

ASP.NET Core 中的区域

作者:Dhananjay KumarRick Anderson

区域是 ASP.NET 功能,用于将相关功能以单独的名称空间(用于路由)和文件夹结构(用于视图)的形式组织到一个组中。 使用区域通过为 controlleraction 或 Razor Page page 添加其他路由参数 area,创建用于路由目的的层次结构。

区域提供了一种将 ASP.NET Core Web 应用划分为更小的功能组的方法,每个功能组都有自己的一组 Razor Pages、控制器、视图和模型。 区域实际上是应用内的结构。 在 ASP.NET Core Web 项目中,Pages、模型、控制器和视图等逻辑组件保存在不同的文件夹中。 ASP.NET Core 运行时使用命名约定来创建这些组件之间的关系。 对于大型应用,将应用分区为独立的高级功能区域可能更有利。 例如,具有多个业务单位(如结账、计费、搜索等)的电子商务应用。 每个单位都有自己的区域,以包含视图、控制器、Razor Pages 和模型。

如果发生以下情况,请考虑在项目中使用区域:

  • 应用由可以进行逻辑分隔的多个高级功能组件组成。
  • 想对应用进行分区,以便可以独立处理每个功能区域。

查看或下载示例代码如何下载)。 下载示例提供了用于测试区域的基本应用。

如果使用 Razor Pages,请参阅本文档中的使用 Razor Pages 的区域

带视图的控制器区域

使用区域、控制器和视图的典型 ASP.NET Core Web 应用包含以下内容:

  • 区域文件夹结构

  • 使用 [Area] 属性将自己与区域关联的控制器:

    [Area("Products")]
    public class ManageController : Controller
    {
    
  • 添加到启动的区域路由

    app.UseMvc(routes =>
    {
        routes.MapRoute(
          name: "MyArea",
          template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
    
        routes.MapRoute(
           name: "default",
           template: "{controller=Home}/{action=Index}/{id?}");
    });
    

区域文件夹结构

请考虑具有两个逻辑组(产品和服务)的应用 。 使用区域,文件夹结构类似于以下内容:

  • 项目名称
    • Areas
      • Products
        • Controllers
          • HomeController.cs
          • ManageController.cs
        • Views
          • Home
            • Index.cshtml
          • Manage
            • Index.cshtml
            • About.cshtml
      • Services
        • Controllers
          • HomeController.cs
        • 视图
          • Home
            • Index.cshtml

虽然前面的布局是使用区域时的典型布局,但只需要视图文件即可使用此文件夹结构。 视图发现按以下顺序搜索匹配的区域视图文件:

/Areas/<Area-Name>/Views/<Controller-Name>/<Action-Name>.cshtml
/Areas/<Area-Name>/Views/Shared/<Action-Name>.cshtml
/Views/Shared/<Action-Name>.cshtml
/Pages/Shared/<Action-Name>.cshtml

将控制器与区域关联

使用[区域]属性指定区域控制器:

using Microsoft.AspNetCore.Mvc;

namespace MVCareas.Areas.Products.Controllers
{
    [Area("Products")]
    public class ManageController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult About()
        {
            return View();
        }
    }
}

添加区域路由

区域路由通常使用传统路由,而不使用属性路由。 传统路由依赖于顺序。 一般情况下,具有区域的路由应放在路由表中靠前的位置,因为它们比没有区域的路由更特定。

如果所有区域的 url 空间一致,则 {area:...} 可用作路由模板中的令牌:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
          name: "MyArea",
          template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

        routes.MapRoute(
           name: "default",
           template: "{controller=Home}/{action=Index}/{id?}");
    });
}

在前面的代码中,exists 应用了路由必须与区域匹配的约束。 使用 {area:...} 是将路由添加到区域的最简单的机制。

以下代码使用 MapAreaRoute 创建两个命名区域路由:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

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

        routes.MapAreaRoute(
            name: "MyAreaServices",
            areaName: "Services",
            template: "Services/{controller=Home}/{action=Index}/{id?}");

        routes.MapRoute(
           name: "default",
           template: "{controller=Home}/{action=Index}/{id?}");
    });
}

MapAreaRoute 与 ASP.NET Core 2.2 配合使用时,请参阅此 GitHub 问题

有关详细信息,请参阅区域路由

示例下载中的以下代码显示指定区域的链接生成:

<li>Anchor Tag Helper links</li>
<ul>
    <li>
        <a asp-area="Products" asp-controller="Home" asp-action="About">
            Products/Home/About
        </a>
    </li>
    <li>
        <a asp-area="Services" asp-controller="Home" asp-action="About">
            Services About
        </a>
    </li>
    <li>
        <a asp-area="" asp-controller="Home" asp-action="About">
            /Home/About
        </a>
    </li>
</ul>
<li>Html.ActionLink generated links</li>
<ul>
    <li>
        @Html.ActionLink("Product/Manage/About", "About", "Manage", 
                                                new { area = "Products" })
    </li>
</ul>
<li>Url.Action generated links</li>
<ul>
    <li>
        <a href='@Url.Action("About", "Manage", new { area = "Products" })'>
            Products/Manage/About
        </a>
    </li>
</ul>

使用上述代码生成的链接在应用的任何位置都有效。

示例下载包含部分视图,该视图包含以前的链接和相同的链接(未指定区域)。 布局文件中引用部分视图,因此应用中的每个页面都显示生成的链接。 在未指定区域的情况下生成的链接仅在从同一区域和控制器中的页面引用时才有效。

如果未指定区域或控制器,路由取决于环境值 。 当前请求的当前路由值被视为链接生成的环境值。 在许多情况下,对于示例应用,使用环境值会生成错误的链接。

有关详细信息,请参阅路由到控制器操作

使用 _ViewStart.cshtml 文件的共享区域布局

要共享整个应用的常用布局,请将 _ViewStart.cshtml 移动到应用程序根文件夹 。

_ViewImports.cshtml

在其标准位置,/Views/_ViewImports.cshtml 不适用于区域 。 若要在区域中使用常用的标记帮助程序@using@inject,确保将正确的 _ViewImports.cshtml 文件应用于区域视图 如果希望所有视图都具有相同的行为,请将 /Views/_ViewImports.cshtml 迁移到应用程序根 。

更改存储视图的默认区域文件夹

以下代码将默认的区域文件夹从 "Areas" 改为"MyAreas"

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RazorViewEngineOptions>(options =>
    {
        options.AreaViewLocationFormats.Clear();
        options.AreaViewLocationFormats.Add("/MyAreas/{2}/Views/{1}/{0}.cshtml");
        options.AreaViewLocationFormats.Add("/MyAreas/{2}/Views/Shared/{0}.cshtml");
        options.AreaViewLocationFormats.Add("/Views/Shared/{0}.cshtml");
    });

    services.AddMvc();
}

使用 Razor Pages 的区域

使用 Razor Pages 的区域需要在应用根目录中有一个 Areas//Pages 文件夹。 以下文件夹结构用于示例应用

  • 项目名称
    • Areas
      • Products
        • Pages
          • _ViewImports
          • About
          • Index
      • Services
        • Pages
          • Manage
            • About
            • Index

示例下载中的以下代码显示指定区域(例如 asp-area="Products")的链接生成:

<li>Anchor Tag Helper links</li>
<ul>
    <li>
        <a asp-area="Products" asp-page="/About">
            Products/About
        </a>
    </li>
    <li>
        <a asp-area="Services" asp-page="/Manage/About">
            Services/Manage/About
        </a>
    </li>
    <li>
        <a asp-area="" asp-page="/About">
            /About
        </a>
    </li>
</ul>
<li>Url.Page generated links</li>
<ul>
    <li>
        <a href='@Url.Page("/Manage/About", new { area = "Services" })'>
            Services/Manage/About
        </a>
    </li>
    <li>
        <a href='@Url.Page("/About", new { area = "Products" })'>
            Products/About
        </a>
    </li>
</ul>

使用上述代码生成的链接在应用的任何位置都有效。

示例下载包含部分视图,该视图包含以前的链接和相同的链接(未指定区域)。 布局文件中引用部分视图,因此应用中的每个页面都显示生成的链接。 在未指定区域的情况下生成的链接仅在从同一区域中的页引用时才有效。

如果未指定区域,路由取决于环境 值。 当前请求的当前路由值被视为链接生成的环境值。 在许多情况下,对于示例应用,使用环境值会生成错误的链接。 例如,考虑从下面的代码生成的链接:

<li>
    <a asp-page="/Manage/About">
        Services/Manage/About
    </a>
</li>
<li>
    <a asp-page="/About">
        /About
    </a>
</li>

对于上述代码:

  • 只有当最后一个请求是针对 Services 区域的页时,从 <a asp-page="/Manage/About"> 生成的链接才是正确的。 例如 /Services/Manage//Services/Manage/Index/Services/Manage/About
  • 只有当最后一个请求是针对 /Home 中的页时,从 <a asp-page="/About"> 生成的链接才是正确的。
  • 代码摘自示例下载

使用 _ViewImports 文件导入命名空间和标记帮助程序

可向每个区域“页面”文件夹添加一个 _ViewImports.cshtml 文件,以将命名空间和标记帮助器导入到该文件夹的每个 Razor 页面中 。

请考虑使用示例代码的“服务”区域,它不包含 _ViewImports.cshtml 文件 。 以下标记显示 /Services/Manage/About Razor Page:

@page
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model RPareas.Areas.Services.Pages.Manage.AboutModel
@{
    ViewData["Title"] = "Srv Mng About";
}

<h2>/Services/Manage/About</h2>

<a asp-area="Products" asp-page="/Index">
    Products/Index
</a>

在前面的标记中:

  • 必须使用完全限定的域名来指定模型 (@model RPareas.Areas.Services.Pages.Manage.AboutModel)。
  • 标记帮助程序@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 启动

在示例下载中,“产品”区域包含下列 _ViewImports.cshtml 文件 :

@namespace RPareas.Areas.Products.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

以下标记显示 /Products/About Razor Page:

@page
@model AboutModel
@{
    ViewData["Title"] = "Prod About";
}

<h2>Products/About</h2>

<a asp-area="Services" asp-page="/Manage/About">
    Services/Manage/About
</a>

在前面的文件中,命名空间和 @addTagHelper 指令通过 Areas/Products/Pages/_ViewImports.cshtml 文件导入到文件中。

有关详细信息,请参阅管理标记帮助程序范围导入共享指令

Razor Pages 区域的共享布局

要共享整个应用的常用布局,请将 _ViewStart.cshtml 移动到应用程序根文件夹 。

发布区域

当 *.csproj 文件中包含 <Project Sdk="Microsoft.NET.Sdk.Web"> 时,所有 *.cshtml 文件以及 wwwroot 目录中的文件都将发布到输出中 。