ASP.NET Core の区分

作成者: Dhananjay Kumar および Rick Anderson

区分は、関連する機能を個別のグループとしてまとめるために使用される ASP.NET の機能です。

  • ルーティング用の名前空間。
  • ビューおよび Razor Pages のフォルダー構造。

ルーティングを行うために、区分を使用して、別のルート パラメーター areacontrolleraction または Razor Page の page に追加して階層を作成します。

領域は、ASP.NET Core Web アプリを小さな機能グループに分割する方法を提供します。それぞれに独自のページ、コントローラー、ビュー、モデルのRazorセットがあります。 区分は、実質的にはアプリ内の構造体となります。 ASP.NET Core Web プロジェクトでは、ページ、モデル、コントローラー、ビューなどの論理コンポーネントが別々のフォルダーに保存されます。 ASP.NET Core ランタイムでは、名前付け規則を使用し、これらのコンポーネント間のリレーションシップを作成します。 大きなアプリでは、アプリを機能の個別の高レベル区分に分割すると便利な場合があります。 チェックアウト、請求、検索などの複数のビジネス ユニットがある eコマース アプリの場合です。 これらのユニットにはそれぞれ、ビュー、コントローラー、Razor Pages、モデルを格納する区分があります。

次のような場合は、プロジェクトで区分を使用することを検討してください。

  • 論理的に大まかに区切れる複数の機能コンポーネントでアプリが構成されている。
  • 各機能区分を個別に使用できるようにアプリを分割したい。

Razor Pages を使用している場合は、このドキュメントの「Razor Pages がある区分」をご覧ください。

ビューを伴うコントローラーの区分

区分、コントローラー、ビューを使用する一般的な ASP.NET Core Web アプリに含まれる内容:

  • 区分フォルダーの構造

  • コントローラーと区分を関連付けるための [Area] 属性を持つコントローラー:

    [Area("Products")]
    public class ManageController : Controller
    {
    
  • 次に追加されたProgram.csエリア ルート:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllersWithViews();
    
    var app = builder.Build();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "MyArea",
        pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    app.Run();
    

区分フォルダーの構造

あるアプリに ProductsServices という 2 つの論理グループが与えられているとします。 区分を利用すると、フォルダーの構造は次のようになります。

  • プロジェクト名
    • 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;
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:...} を使用できます。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

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

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

app.Run();

上記のコードでは、ルートは 1 つの区分に一致しなければならないという制約が exists によって適用されます。 {area:...}MapControllerRoute を使用することは、次のことを意味します。

  • これは、ルーティングを区分に追加するメカニズムとして最も単純である。
  • [Area("Area name")] 属性を持つすべてのコントローラーに一致する。

次のコードでは、MapAreaControllerRoute を使用し、名前の付いた区分ルートが 2 つ作成されます。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

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

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

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

app.Run();

詳細については、区分のルーティングに関するページを参照してください。

サンプル ダウンロードに含まれる次のコードでは、区分が指定された上でリンクが生成されます。

<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.cshtml を格納します。 詳細については、「ASP.NET Coreのレイアウト」を参照してください。

アプリケーションのルート フォルダー

アプリケーション ルート フォルダーは、ASP.NET Core テンプレートで作成された Web アプリ内のファイルを含むProgram.csフォルダーです。

_ViewImports.cshtml

MVC の /Views/_ViewImports.cshtml と、Razor Pages の /Pages/_ViewImports.cshtml は区分のビューにインポートされません。 次のいずれかの方法を使用して、ビューをすべてのビューにインポートします。

  • アプリケーションのルート フォルダー_ViewImports.cshtml を追加します。 アプリケーションのルート フォルダー内の _ViewImports.cshtml は、アプリ内のすべてのビューに適用されます。
  • 区分の下にある適切なビュー フォルダーに _ViewImports.cshtml ファイルをコピーします。 たとえば、個々の Razor ユーザー アカウントで作成された Pages アプリには、次のフォルダーに _ViewImports.cshtml ファイルがあります。
    • /Areas/Identity/Pages/_ViewImports.cshtml
    • /Pages/_ViewImports.cshtml

_ViewImports.cshtml ファイルには、通常、タグ ヘルパー のインポート、@using@inject ステートメントが含まれます。 詳細については、「共有ディレクティブのインポート」を参照してください。

ビューが保存されている既定の区分フォルダーを変更する

次のコードでは、既定の区分フォルダーが "Areas" から "MyAreas" に変更されます。

using Microsoft.AspNetCore.Mvc.Razor;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

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

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

app.Run();

Razor Pages がある区分

Razor Pages がある区分には、アプリのルートに 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>

上のコードの場合:

  • <a asp-page="/Manage/About"> から生成されるリンクは、前回の要求が Services 区分内のページに向けられていた場合にのみ正しくなります。 たとえば、「/Services/Manage/」、「/Services/Manage/Index」、「/Services/Manage/About」のように指定します。
  • <a asp-page="/About"> から生成されるリンクは、前回の要求が /Home 内のページに向けられていた場合にのみ正しくなります。
  • コードは、サンプル ダウンロードからのものです。

_ViewImports ファイルを使って名前空間とタグ ヘルパーをインポートする

_ViewImports.cshtml ファイルを各区分の Pages フォルダーに追加して、フォルダー内の各 Razor ページに名前空間とタグ ヘルパーをインポートすることができます。

サンプル コードの Services 区分について検討します。これには _ViewImports.cshtml ファイルが含まれていません。 次のマークアップは、 /Services/Manage/AboutRazor ページを示しています。

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

<div>
  ViewData["routeInfo"]:  @ViewData["routeInfo"]
</div>

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

上のマークアップについて:

  • 完全修飾クラス名を使ってモデルを指定する必要があります (@model RPareas.Areas.Services.Pages.Manage.AboutModel)。
  • タグ ヘルパー@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers によって有効になります

サンプル ダウンロードでは、Products 区分に次の _ViewImports.cshtml ファイルが含まれています。

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

次のマークアップは 、/Products/AboutRazor ページを示しています。

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

上のファイルでは、Areas/Products/Pages/_ViewImports.cshtml ファイルによって、名前空間と @addTagHelper ディレクティブがファイルにインポートされています。

詳細については、「タグ ヘルパーのスコープの管理」と「共有ディレクティブのインポート」をご覧ください。

Razor Pages 区分の共有レイアウト

アプリ全体で共通レイアウトを共有するには、アプリケーションのルート フォルダーに _ViewStart.cshtml を移動します。

区分の発行

*.csproj ファイルに <Project Sdk="Microsoft.NET.Sdk.Web"> が含まれているときは、すべての *.cshtml ファイル、および wwwroot ディレクトリ内のファイルが出力に発行されます。

Visual Studio を使用して MVC 区分を追加する

ソリューション エクスプローラーで、プロジェクトを右クリックし、[新しいスキャフォールディングされた項目の追加>] を選択してから、[MVC 領域] を選択します。

その他のリソース

区分は、関連する機能を個別のグループとしてまとめるために使用される ASP.NET の機能です。

  • ルーティング用の名前空間。
  • ビューおよび Razor Pages のフォルダー構造。

ルーティングを行うために、区分を使用して、別のルート パラメーター areacontrolleraction または Razor Page の page に追加して階層を作成します。

領域は、ASP.NET Core Web アプリを小さな機能グループに分割する方法を提供します。それぞれに独自のページ、コントローラー、ビュー、モデルのRazorセットがあります。 区分は、実質的にはアプリ内の構造体となります。 ASP.NET Core Web プロジェクトでは、ページ、モデル、コントローラー、ビューなどの論理コンポーネントが別々のフォルダーに保存されます。 ASP.NET Core ランタイムでは、名前付け規則を使用し、これらのコンポーネント間のリレーションシップを作成します。 大きなアプリでは、アプリを機能の個別の高レベル区分に分割すると便利な場合があります。 チェックアウト、請求、検索などの複数のビジネス ユニットがある eコマース アプリの場合です。 これらのユニットにはそれぞれ、ビュー、コントローラー、Razor Pages、モデルを格納する区分があります。

次のような場合は、プロジェクトで区分を使用することを検討してください。

  • 論理的に大まかに区切れる複数の機能コンポーネントでアプリが構成されている。
  • 各機能区分を個別に使用できるようにアプリを分割したい。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。 ダウンロード サンプルからは、区分をテストするための基本的なアプリが与えられます。

Razor Pages を使用している場合は、このドキュメントの「Razor Pages がある区分」をご覧ください。

ビューを伴うコントローラーの区分

区分、コントローラー、ビューを使用する一般的な 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?}");
    });
    

区分フォルダーの構造

あるアプリに ProductsServices という 2 つの論理グループが与えられているとします。 区分を利用すると、フォルダーの構造は次のようになります。

  • プロジェクト名
    • 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;
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?}");
    });
}

上記のコードでは、ルートは 1 つの区分に一致しなければならないという制約が exists によって適用されます。 {area:...}MapControllerRoute を使用することは、次のことを意味します。

  • これは、ルーティングを区分に追加するメカニズムとして最も単純である。
  • [Area("Area name")] 属性を持つすべてのコントローラーに一致する。

次のコードでは、MapAreaControllerRoute を使用し、名前の付いた区分ルートが 2 つ作成されます。

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.cshtmlルート フォルダーに保存します。 詳細については、「ASP.NET Coreのレイアウト」を参照してください。

アプリケーションのルート フォルダー

アプリケーション ルート フォルダーは、ASP.NET Core テンプレートで作成された Web アプリに含まれるStartup.csフォルダーです。

_ViewImports.cshtml

/Views/_ViewImports.cshtml、MVC の場合、および /Pages/_ViewImports.cshtml Pages の場合 Razor 、領域のビューにはインポートされません。 次のいずれかの方法を使用して、ビューをすべてのビューにインポートします。

  • アプリケーションのルート フォルダーに追加_ViewImports.cshtmlします。 アプリケーション ルート フォルダー内の A _ViewImports.cshtml は、アプリ内のすべてのビューに適用されます。
  • 領域の _ViewImports.cshtml 下の適切なビュー フォルダーにファイルをコピーします。

この _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 Pages がある区分

Razor Pages がある区分には、アプリのルートに 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>

上のコードの場合:

  • <a asp-page="/Manage/About"> から生成されるリンクは、前回の要求が Services 区分内のページに向けられていた場合にのみ正しくなります。 たとえば、「/Services/Manage/」、「/Services/Manage/Index」、「/Services/Manage/About」のように指定します。
  • <a asp-page="/About"> から生成されるリンクは、前回の要求が /Home 内のページに向けられていた場合にのみ正しくなります。
  • コードは、サンプル ダウンロードからのものです。

_ViewImports ファイルを使って名前空間とタグ ヘルパーをインポートする

_ViewImports.cshtml各領域 Pages フォルダーにファイルを追加して、名前空間とタグ ヘルパーをフォルダー内の各Razorページにインポートできます。

ファイルが含まれていないサンプル コードの [サービス ] 領域について _ViewImports.cshtml 考えてみましょう。 次のマークアップは、 /Services/Manage/AboutRazor ページを示しています。

@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/AboutRazor ページを示しています。

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

上記のファイルでは、名前空間と @addTagHelper ディレクティブがファイルによってファイルに Areas/Products/Pages/_ViewImports.cshtml インポートされます。

詳細については、「タグ ヘルパーのスコープの管理」と「共有ディレクティブのインポート」をご覧ください。

Razor Pages 区分の共有レイアウト

アプリ全体の共通レイアウトを共有するには、アプリケーションの _ViewStart.cshtml ルート フォルダーに移動します。

区分の発行

*.csproj ファイルに <Project Sdk="Microsoft.NET.Sdk.Web"> が含まれているときは、すべての *.cshtml ファイル、および wwwroot ディレクトリ内のファイルが出力に発行されます。

Visual Studio を使用して MVC 区分を追加する

ソリューション エクスプローラーでプロジェクトを右クリックし、[新しいスキャフォールディングされた項目の追加>] を選択してから、[MVC 領域] を選択します。

区分は ASP.NET の機能であり、関連する機能を別の名前空間 (ルーティングの場合) およびフォルダー構造 (ビューの場合) としてグループにまとめるために使用されます。 ルーティングを行うために、区分を使用して、別のルート パラメーター areacontrolleraction または Razor Page の page に追加して階層を作成します。

領域を使用すると、ASP.NET Core Web アプリをより小さな機能グループに分割し、それぞれに独自のページ、コントローラー、ビュー、モデルのRazorセットを使用できます。 区分は、実質的にはアプリ内の構造体となります。 ASP.NET Core Web プロジェクトでは、ページ、モデル、コントローラー、ビューなどの論理コンポーネントが別々のフォルダーに保存されます。 ASP.NET Core ランタイムでは、名前付け規則を使用し、これらのコンポーネント間のリレーションシップを作成します。 大きなアプリでは、アプリを機能の個別の高レベル区分に分割すると便利な場合があります。 チェックアウト、請求、検索などの複数のビジネス ユニットがある eコマース アプリの場合です。 これらのユニットにはそれぞれ、ビュー、コントローラー、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?}");
    });
    

区分フォルダーの構造

あるアプリに ProductsServices という 2 つの論理グループが与えられているとします。 区分を利用すると、フォルダーの構造は次のようになります。

  • プロジェクト名
    • 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?}");
    });
}

上記のコードでは、ルートは 1 つの区分に一致しなければならないという制約が exists によって適用されます。 {area:...} の使用は、ルーティングを区分に追加するメカニズムとして最も単純です。

次のコードでは、MapAreaRoute を使用し、名前の付いた区分ルートが 2 つ作成されます。

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

ASP.NET Core 2.2 で MapAreaRoute を使用するときは、この 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/<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>

上のコードの場合:

  • <a asp-page="/Manage/About"> から生成されるリンクは、前回の要求が Services 区分内のページに向けられていた場合にのみ正しくなります。 たとえば、「/Services/Manage/」、「/Services/Manage/Index」、「/Services/Manage/About」のように指定します。
  • <a asp-page="/About"> から生成されるリンクは、前回の要求が /Home 内のページに向けられていた場合にのみ正しくなります。
  • コードは、サンプル ダウンロードからのものです。

_ViewImports ファイルを使って名前空間とタグ ヘルパーをインポートする

_ViewImports.cshtml各領域の Pages フォルダーにファイルを追加して、フォルダー内の各Razorページに名前空間とタグ ヘルパーをインポートできます。

サンプル コードの サービス 領域 (ファイルが含 _ViewImports.cshtml まれていないもの) について考えてみます。 次のマークアップは、 /Services/Manage/AboutRazor ページを示しています。

@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/AboutRazor ページを示しています。

@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 ディレクトリ内のファイルが出力に発行されます。