ASP.NET Core 中的区域

作者:Dhananjay KumarRick Anderson

区域是一项 ASP.NET 功能,用于将相关功能作为单独的组进行组织:

  • 用于路由的命名空间。
  • 视图和页面的文件夹结构 Razor 。

使用区域通过向 area controlleraction 或 Razor 页添加另一个路由参数来创建用于路由目的的层次结构 page

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

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

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

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

如果使用的是 Razor 页面,请参阅本文档中 包含 Razor 页面的区域

带视图的控制器区域

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

  • 区域文件夹结构

  • 具有属性的控制器 [Area] 用于将控制器与区域关联:

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

    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?}");
    });
    

区域文件夹结构

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

  • 项目名称
    • Areas
      • 产品
        • 控制器
          • Home控制器 .cs
          • ManageController.cs
        • 视图
          • Home
            • Index.cshtml
          • 管理
            • Index.cshtml
            • About.cshtml
      • 服务
        • 控制器
          • Home控制器 .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

将控制器与区域关联

区域控制器是用 [ area ] 特性指定的:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Docs.Samples;

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

        public IActionResult About()
        {
            ViewData["routeInfo"] = ControllerContext.MyDisplayRouteInfo();
            return View();
        }
    }
}

添加区域路由

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

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

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

    app.UseRouting();

    app.UseAuthorization();

    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?}");
    });
}

在前面的代码中,exists 应用了路由必须与区域匹配的约束。 使用 {area:...} MapControllerRoute

  • 是将路由添加到区域的最不复杂的机制。
  • 将所有控制器与属性进行匹配 [Area("Area name")]

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

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

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapAreaControllerRoute(
            name: "MyAreaProducts",
            areaName: "Products",
            pattern: "Products/{controller=Home}/{action=Index}/{id?}");

        endpoints.MapAreaControllerRoute(
            name: "MyAreaServices",
            areaName: "Services",
            pattern: "Services/{controller=Home}/{action=Index}/{id?}");

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

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

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

<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>

示例下载包含 部分视图 ,其中包含:

  • 前面的链接。
  • 与前面的链接相似,但 area 未指定。

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

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

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

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

若要为整个应用共享公共布局,请在 应用程序根文件夹中保留 _ViewStart。 有关详细信息,请参阅 ASP.NET Core 中的布局

应用程序根文件夹

应用程序根文件夹是一个文件夹,其中包含通过 ASP.NET Core 模板创建的 web 应用中的 Startup。

_ViewImports.cshtml

对于 MVC, _ViewImports 的/Views//Pages/_ViewImports Razor ,不会导入到区域中的视图。 使用以下方法之一来提供所有视图的视图导入:

  • _ViewImports 添加到 应用程序根文件夹。 应用程序根文件夹中的 _ViewImports 将应用到应用中的所有视图。
  • _ViewImports 的文件复制到 "区域" 下的相应视图文件夹中。

_ViewImports 的 cshtml 文件通常包含 标记帮助程序导入、 @using@inject 语句。 有关详细信息,请参阅 导入共享指令

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

以下代码将默认的区域文件夹从 "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.AddControllersWithViews();
}

包含页面的区域 Razor

包含页面的区域 Razor Areas/<area name>/Pages 在应用的根目录中需要一个文件夹。 以下文件夹结构用于示例应用

  • 项目名称
    • Areas
      • 产品
          • _ViewImports
          • 关于
          • 索引
      • 服务
          • 管理
            • 关于
            • 索引

示例下载中的以下代码显示指定区域(例如 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 文件添加到每个区域 Pages 文件夹,以将命名空间和标记帮助程序导入到文件夹的每个 Razor 页面。

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

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

<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
@model AboutModel
@{
    ViewData["Title"] = "Prod About";
}

在上一文件中,namespace 和 指令由 @addTagHelper Areas/Products/Pages/_ViewImports.cshtml 文件导入到该文件。

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

Pages 区域共享 Razor 布局

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

发布区域

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

添加 MVC 区域Visual Studio

在解决方案资源管理器中,右键单击项目并选择"添加 >""新基架项",然后选择 "MVC 区域"。

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

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

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

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

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

如果使用 Pages,请参阅 Razor 本文档中的 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
      • 产品
        • 控制器
          • HomeController.cs
          • ManageController.cs
        • 视图
          • Home
            • Index.cshtml
          • 管理
            • Index.cshtml
            • About.cshtml
      • 服务
        • 控制器
          • 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

将控制器与区域关联

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

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

包含页面的区域 Razor Areas/<area name>/Pages 在应用的根目录中需要一个文件夹。 以下文件夹结构用于示例应用

  • 项目名称
    • Areas
      • 产品
          • _ViewImports
          • 关于
          • 索引
      • 服务
          • 管理
            • 关于
            • 索引

示例下载中的以下代码显示指定区域(例如 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
@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
@model AboutModel
@{
    ViewData["Title"] = "Prod About";
}

<h2>Products/About</h2>

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

在前面的文件中,将 @addTagHelper区域/产品/页面/_ViewImports cshtml 文件将命名空间和指令导入文件。

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

页面区域的共享布局 Razor

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

发布区域

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