ASP.NET Core のビュー コンポーネント
作成者: Rick Anderson
ビュー コンポーネント
ビュー コンポーネントは部分ビューと似ていますが、はるかに強力なものです。 ビュー コンポーネントはモデル バインドを使用せず、ビュー コンポーネントを呼び出すときに渡されるデータに依存します。 この記事はコントローラーとビューを使用して記述されましたが、ビュー コンポーネントは Pages で Razor 動作します。
ビュー コンポーネントの特徴は次のとおりです。
- 応答全体ではなく、チャンクをレンダリングします。
- コントローラーとビューの間にあるのと同じ関心の分離とテストの容易性の利点があります。
- パラメーターとビジネス ロジックを含めることができます。
- 通常、レイアウト ページから呼び出されます。
ビュー コンポーネントは、次のような部分ビューに対して複雑すぎる再利用可能なレンダリング ロジックを目的としています。
- 動的なナビゲーション メニュー
- データベースにクエリを実行するクラウドにタグを付ける
- サインイン パネル
- ショッピング カート
- 新着情報の記事
- ブログのサイドバー コンテンツ
- ユーザーのサインイン状態に応じて、すべてのページに表示され、サインアウトまたはサインインするリンクが表示されるサインイン パネル
ビュー コンポーネントは、次の 2 つの部分で構成されます。
- このクラスは、通常、次から派生します。 ViewComponent
- 返される結果 (通常はビュー)。
コントローラーと同様に、ビュー コンポーネントは POCO にすることができますが、ほとんどの開発者は、派生 ViewComponentして使用できるメソッドとプロパティを利用します。
ビュー コンポーネントが、アプリの仕様を満たしているかどうかを検討する場合は、代わりに Razor コンポーネントを使用することを検討してください。 Razor コンポーネントでも、C# コードとマークアップを組み合わせて、再利用可能な UI ユニットを生成できます。 Razor コンポーネントは、クライアント側で UI ロジックと構成を提供する場合の開発者の生産性のために設計されています。 詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。 MVC または Pages アプリにコンポーネントを組み込むRazor方法については、「Prerender と ASP.NET Core コンポーネントのRazor統合」を参照してください。Razor
ビュー コンポーネントを作成する
このセクションには、ビュー コンポーネントを作成するための高レベルの要件が含まれています。 記事の後半で、各ステップの詳細を検証し、ビュー コンポーネントを作成します。
ビュー コンポーネント クラス
ビュー コンポーネント クラスは、次のいずれかによって作成できます。
- 派生 ViewComponent
[ViewComponent]
属性でクラスを装飾するか、[ViewComponent]
属性でクラスから派生させる- 名前がサフィックスで終わるクラスの作成
ViewComponent
コントローラーと同様に、ビュー コンポーネントは、パブリック クラス、入れ子にされていないクラス、および非抽象クラスである必要があります。 ビュー コンポーネント名は、サフィックスが削除された ViewComponent
クラス名です。 また、これは Name プロパティを使用して、明示的に指定することもできます。
ビュー コンポーネント クラスの特徴は次のとおりです。
大文字と小文字を区別しない ViewComponent
サフィックスを持つクラスがビュー コンポーネントとして扱われないようにするには、属性を使用してクラスを [NonViewComponent]
装飾します。
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
ビュー コンポーネント メソッド
ビュー コンポーネントでは、次のロジックが定義されます。
InvokeAsync
を返すTask<IViewComponentResult>
メソッドです。Invoke
を返す IViewComponentResult同期メソッドです。
パラメーターは、モデル バインドではなく、ビュー コンポーネントから直接取得します。 ビュー コンポーネントが要求を直接処理することはありません。 通常、ビュー コンポーネントは、モデルを初期化し、View
メソッドを呼び出してビューに渡します。 要約すると、ビュー コンポーネント メソッドの特徴は次のとおりです。
Task<IViewComponentResult>
を返すInvokeAsync
メソッドまたはIViewComponentResult
を返す同期Invoke
メソッドを定義します。- 通常、モデルを初期化し、 ViewComponent.View メソッドを呼び出してビューに渡します。
- パラメーターは HTTP ではなく、呼び出し元のメソッドから取得されます。 モデル バインドはありません。
- HTTP エンドポイントとして直接到達できません。 通常、これらはビューで呼び出されます。 ビュー コンポーネントでは要求が処理されません。
- 現在の HTTP 要求からの詳細ではなく、シグネチャでオーバーロードされます。
ビューの検索パス
ランタイムでは、次のパスでビューを検索します。
- /Views/{コントローラー名}/Components/{ビュー コンポーネント名}/{ビュー名}
- /Views/Shared/Components/{ビュー コンポーネント名}/{ビュー名}
- /Pages/Shared/Components/{ビュー コンポーネント名}/{ビュー名}
この検索パスは、コントローラーとビューおよび Razor Pages を使うプロジェクト用です。
ビュー コンポーネントの既定のビュー名は Default
、ビュー ファイルの名前 Default.cshtml
が通常であることを意味します。 ビュー コンポーネントの結果を作成するとき、またはメソッドを呼び出すときに、別のビュー名を View
指定できます。
ビュー ファイル Default.cshtml
に名前を付け、 Views/Shared/Components/{View Component Name}/{View Name} パスを使用することをお勧めします。 このサンプルで使用するビュー コンポーネントは PriorityList
、ビュー コンポーネント ビューに使用 Views/Shared/Components/PriorityList/Default.cshtml
します。
ビューの検索パスをカスタマイズする
ビューの検索パスをカスタマイズするには、Razor の ViewLocationFormats コレクションを変更します。 たとえば、パス /Components/{View Component Name}/{View Name}
内のビューを検索するには、コレクションに新しい項目を追加します。
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
前のコードでは、プレースホルダー {0}
はパス Components/{View Component Name}/{View Name}
を表します。
ビュー コンポーネントを呼び出す
ビュー コンポーネントを使用するには、ビュー内で以下を呼び出します。
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
パラメーターはメソッドに InvokeAsync
渡されます。 アーティ PriorityList
クルで開発されたビュー コンポーネントは、ビュー ファイルから Views/ToDo/Index.cshtml
呼び出されます。 次のコードでは、メソッドは InvokeAsync
2 つのパラメーターを使用して呼び出されます。
</table>
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
ビュー コンポーネントをタグ ヘルパーとして呼び出す
ビュー コンポーネントは、 タグ ヘルパーとして呼び出すことができます。
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
タグ ヘルパーのパスカル ケースのクラスとメソッドのパラメーターは、それぞれケバブ ケースに変換されます。 ビュー コンポーネントを呼び出すタグ ヘルパーでは、<vc></vc>
要素を使用します。 ビュー コンポーネントは、次のように指定されます。
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
ビュー コンポーネントをタグ ヘルパーとして使用するには、@addTagHelper
ディレクティブを使用して、ビュー コンポーネントを含むアセンブリを登録します。 ビュー コンポーネントが呼び出された MyWebApp
アセンブリ内にある場合は、次のディレクティブをファイルに _ViewImports.cshtml
追加します。
@addTagHelper *, MyWebApp
ビュー コンポーネントは、ビュー コンポーネントを参照する任意のファイルにタグ ヘルパーとして登録できます。 タグ ヘルパーを登録する方法の詳細については、「Managing Tag Helper Scope」 (タグ ヘルパーのスコープの管理) を参照してください。
このチュートリアルで使用される InvokeAsync
メソッドは、次のとおりです。
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
上記のマークアップでは、ビュー コンポーネントは PriorityList
priority-list
. ビュー コンポーネントに対するパラメーターは、ケバブ ケースの属性として渡されます。
コントローラーからビュー コンポーネントを直接呼び出す
ビュー コンポーネントは通常、ビューから呼び出されますが、コントローラー メソッドから直接呼び出すことができます。 ビュー コンポーネントはコントローラーなどのエンドポイントを定義しませんが、コンテンツを返すコントローラー アクションを ViewComponentResult
実装できます。
次の例では、ビュー コンポーネントはコントローラーから直接呼び出されます。
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
基本的なビュー コンポーネントを作成する
スタート コードをダウンロード、ビルド、およびテストします。 これは、ToDo 項目の一覧をToDo
表示するコントローラーを備えた基本的なプロジェクトです。
優先度と完了状態を渡すようにコントローラーを更新する
優先度と完了の Index
状態パラメーターを使用するようにメソッドを更新します。
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
ViewComponent クラスの追加
ViewComponent クラスを次に追加します ViewComponents/PriorityListViewComponent.cs
。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context) => db = context;
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
コードに関する注意事項
ビュー コンポーネント クラスは、プロジェクト内の任意のフォルダーに含めることができます。
クラス名 PriorityListViewComponent はサフィックス ViewComponent で終わるため、ランタイムはビューからクラス コンポーネントを参照するときに文字列
PriorityList
を使用します。[ViewComponent]
属性では、ビュー コンポーネントを参照するために使用する名前を変更できます。 たとえば、次の属性を使用してクラスに名前XYZ
を[ViewComponent]
付けたとします。[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
前のコードの属性は
[ViewComponent]
、ビュー コンポーネント セレクターに使用するように指示します。- コンポーネントに関連付けられているビューを探すときの名前
PriorityList
- ビューからクラス コンポーネントを参照するときの文字列 "PriorityList" です。
- コンポーネントに関連付けられているビューを探すときの名前
コンポーネントでは、依存性の注入を使用して、データ コンテキストを利用できるようにします。
InvokeAsync
はビューから呼び出すことができるメソッドを公開し、任意の数の引数を受け取ることができます。InvokeAsync
メソッドでは、isDone
とmaxPriority
パラメーターを満たすToDo
項目のセットを返します。
ビュー コンポーネント Razor ビューの作成
Views/Shared/Components フォルダーを作成します。 このフォルダーは、Components という名前にする必要があります。
Views/Shared/Components/PriorityList フォルダーを作成します。 このフォルダー名は、ビュー コンポーネント クラスの名前、またはクラスの名前からサフィックスを引いた名前と一致する必要があります。 属性を使用する
ViewComponent
場合、クラス名は属性の指定と一致する必要があります。ビューを作成します
Views/Shared/Components/PriorityList/Default.cshtml
Razor 。@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Razor ビューでは、
TodoItem
のリストを取得してそれらを表示します。 ビュー コンポーネントInvokeAsync
メソッドがビューの名前を渡さない場合は、規則によってビュー名に Default が使用されます。 特定のコントローラーの既定のスタイルをオーバーライドするには、コントローラーに固有のビュー フォルダー (例: Views/ToDo/Components/PriorityList/Default.cshtml) にビューを追加します。ビュー コンポーネントがコントローラー固有の場合は、コントローラー固有のフォルダーに追加できます。 たとえば、
Views/ToDo/Components/PriorityList/Default.cshtml
コントローラー固有です。div
優先度リスト コンポーネントを含む呼び出しをファイルの下部にViews/ToDo/index.cshtml
追加します。</table> <div> Maxium Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
@await Component.InvokeAsync
マークアップは、ビュー コンポーネントを呼び出すための構文を示します。 最初の引数は、呼び出す必要があるコンポーネントの名前です。 後続のパラメーターは、そのコンポーネントに渡されます。 InvokeAsync
では、任意の数の引数を取得できます。
アプリをテストします。 次の画像は、[ToDo] リストと優先順位の項目を示します。
ビュー コンポーネントは、コントローラーから直接呼び出すことができます。
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
ビュー コンポーネント名を指定する
複雑なビュー コンポーネントでは、いくつかの条件下で、既定以外のビューを指定する必要がある場合があります。 次のコードは、メソッドから "PVC" ビューを指定する方法を InvokeAsync
示しています。 PriorityListViewComponent
クラスで InvokeAsync
メソッドを更新します。
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
ファイルを Views/Shared/Components/PriorityList/Default.cshtml
名前付きの Views/Shared/Components/PriorityList/PVC.cshtml
ビューにコピーします。 PVC ビューが使用されていることを示すために、見出しを追加します。
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
アプリを実行して、PVC ビューを確認します。
PVC ビューがレンダリングされない場合は、優先度が 4 以上のビュー コンポーネントが呼び出されていることを確認します。
ビューのパスを調べる
優先順位ビューが返されないように、優先順位パラメーターを 3 以下に変更します。
に一時的に名前を変更します
Views/ToDo/Components/PriorityList/Default.cshtml
1Default.cshtml
。アプリをテストすると、次のエラーが発生します。
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Views/ToDo/Components/PriorityList/1Default.cshtml
をViews/Shared/Components/PriorityList/Default.cshtml
にコピーします。[Shared] の [ToDo] ビュー コンポーネントのビューにマークアップを追加して、そのビューが [Shared] フォルダーからのものであることを示します。
[Shared] コンポーネント ビューをテストします。
ハードコーディングされた文字列を避ける
コンパイル時の安全性を確保するために、ハードコーディングされたビュー コンポーネント名をクラス名に置き換えます。 PriorityListViewComponent.cs ファイルを更新して、"ViewComponent" サフィックスを使用しないようにします。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
ビュー ファイル:
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
CLR 型を受け取るメソッドの Component.InvokeAsync
オーバーロードでは、演算子を typeof
使用します。
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
同期作業を実行する
非同期処理が必要ない場合、フレームワークは同期 Invoke
メソッドの呼び出しを処理します。 次のメソッドでは同期 Invoke
ビュー コンポーネントを作成します。
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
ビュー コンポーネントの Razor ファイル:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
ビュー コンポーネントは、次のいずれかの方法を Razor 使用してファイル (たとえば Views/Home/Index.cshtml
) で呼び出されます。
IViewComponentHelper の方法を使用するには、Component.InvokeAsync
を呼び出します。
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
タグ ヘルパーを使用するには、@addTagHelper
ディレクティブを使用して、ビュー コンポーネントを含むアセンブリを登録します (ビュー コンポーネントは、MyWebApp
と呼ばれるアセンブリ内にあります)。
@addTagHelper *, MyWebApp
Razor マークアップ ファイルでビュー コンポーネントのタグ ヘルパーを使用します。
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
PriorityList.Invoke
のメソッド署名は同期的ですが、Razor ではマークアップ ファイルで Component.InvokeAsync
を使用してメソッドを見つけて呼び出します。
その他の技術情報
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
ビュー コンポーネント
ビュー コンポーネントは部分ビューと似ていますが、はるかに強力なものです。 ビュー コンポーネントでは、モデル バインドを使用せず、呼び出すときに指定されたデータのみに依存します。 この記事はコントローラーとビューを使用して作成されましたが、ビュー コンポーネントは Razor Pages でも利用できます。
ビュー コンポーネントの特徴は次のとおりです。
- 応答全体ではなく、チャンクをレンダリングします。
- コントローラーとビューの間にあるのと同じ関心の分離とテストの容易性の利点があります。
- パラメーターとビジネス ロジックを含めることができます。
- 通常、レイアウト ページから呼び出されます。
ビュー コンポーネントは、次のような部分ビューには複雑すぎる、再利用可能なレンダリング ロジックをどこでも使用できるようにするためのものです。
- 動的なナビゲーション メニュー
- タグ クラウド (データベースをクエリする場所)
- ログイン パネル
- ショッピング カート
- 新着情報の記事
- 一般的なブログのサイドバーのコンテンツ
- すべてのページでレンダリングされ、ユーザーの状態のログに応じて、ログアウトまたはログインのいずれかのリンクを示すログイン パネル
ビュー コンポーネントは、クラス (通常は派生) と返される ViewComponent結果 (通常はビュー) の 2 つの部分で構成されます。 コントローラーと同様に、ビュー コンポーネントは POCO にすることができますが、ほとんどの開発者は、派生 ViewComponent
して使用できるメソッドとプロパティを利用します。
ビュー コンポーネントが、アプリの仕様を満たしているかどうかを検討する場合は、代わりに Razor コンポーネントを使用することを検討してください。 Razor コンポーネントでも、C# コードとマークアップを組み合わせて、再利用可能な UI ユニットを生成できます。 Razor コンポーネントは、クライアント側で UI ロジックと構成を提供する場合の開発者の生産性のために設計されています。 詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。 MVC または Pages アプリにコンポーネントを組み込むRazor方法については、「Prerender と ASP.NET Core コンポーネントのRazor統合」を参照してください。Razor
ビューのコンポーネントを作成する
このセクションには、ビュー コンポーネントを作成するための高レベルの要件が含まれています。 記事の後半で、各ステップの詳細を検証し、ビュー コンポーネントを作成します。
ビュー コンポーネント クラス
ビュー コンポーネント クラスは、次のいずれかによって作成できます。
- ViewComponent から派生させる
[ViewComponent]
属性でクラスを装飾するか、[ViewComponent]
属性でクラスから派生させる- 名前がサフィックス ViewComponent で終わるクラスを作成する
コントローラーと同様に、ビュー コンポーネントは、パブリック クラス、入れ子にされていないクラス、および非抽象クラスである必要があります。 ビュー コンポーネント名は、"ViewComponent" サフィックスを除いたクラス名です。 また、これは ViewComponentAttribute.Name
プロパティを使用して、明示的に指定することもできます。
ビュー コンポーネント クラスの特徴は次のとおりです。
大文字と小文字を区別しない ViewComponent サフィックスを持つクラスがビュー コンポーネントとして処理されないようにするには、クラスを [NonViewComponent] 属性で装飾します。
[NonViewComponent]
public class ReviewComponent
{
// ...
ビュー コンポーネント メソッド
ビュー コンポーネントでは、Task<IViewComponentResult>
を返す InvokeAsync
メソッドまたは IViewComponentResult
を返す同期 Invoke
メソッドでロジックを定義します。 パラメーターは、モデル バインドではなく、ビュー コンポーネントから直接取得します。 ビュー コンポーネントが要求を直接処理することはありません。 通常、ビュー コンポーネントは、モデルを初期化し、View
メソッドを呼び出してビューに渡します。 要約すると、ビュー コンポーネント メソッドの特徴は次のとおりです。
Task<IViewComponentResult>
を返すInvokeAsync
メソッドまたはIViewComponentResult
を返す同期Invoke
メソッドを定義します。- 通常、モデルを初期化し、
ViewComponent
View
メソッドを呼び出してビューに渡します。 - パラメーターは HTTP ではなく、呼び出し元のメソッドから取得されます。 モデル バインドはありません。
- HTTP エンドポイントとして直接到達することはできません。 (通常はビュー内で) コードから呼び出されます。 ビュー コンポーネントでは要求が処理されません。
- 現在の HTTP 要求からの詳細ではなく、シグネチャでオーバーロードされます。
ビューの検索パス
ランタイムでは、次のパスでビューを検索します。
- /Views/{コントローラー名}/Components/{ビュー コンポーネント名}/{ビュー名}
- /Views/Shared/Components/{ビュー コンポーネント名}/{ビュー名}
- /Pages/Shared/Components/{ビュー コンポーネント名}/{ビュー名}
この検索パスは、コントローラーとビューおよび Razor Pages を使うプロジェクト用です。
ビュー コンポーネントの既定のビュー名は Default です。つまり、ビュー ファイルには通常、名前が付けられます Default.cshtml
。 ビュー コンポーネントの結果を作成したり、View
メソッドを呼び出したりするときに、別のビュー名を指定することができます。
ビュー ファイル Default.cshtml
に名前を付け、 Views/Shared/Components/{View Component Name}/{View Name} パスを使用することをお勧めします。 このサンプルで使用するビュー コンポーネントは PriorityList
、ビュー コンポーネント ビューに使用 Views/Shared/Components/PriorityList/Default.cshtml
します。
ビューの検索パスをカスタマイズする
ビューの検索パスをカスタマイズするには、Razor の ViewLocationFormats コレクションを変更します。 たとえば、"/Components/{ビュー コンポーネント名}/{ビュー名}" というパス内のビューを検索するには、次のように新しい項目をコレクションに追加します。
services.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
上記のコードでは、プレースホルダー "{0}" はパス "/Components/{ビュー コンポーネント名}/{ビュー名}" を表しています。
ビュー コンポーネントを呼び出す
ビュー コンポーネントを使用するには、ビュー内で以下を呼び出します。
@await Component.InvokeAsync("Name of view component", {Anonymous Type Containing Parameters})
パラメーターは、InvokeAsync
メソッドに渡されます。 アーティ PriorityList
クルで開発されたビュー コンポーネントは、ビュー ファイルから Views/ToDo/Index.cshtml
呼び出されます。 以下では、InvokeAsync
メソッドは、2 つのパラメーターで呼び出されます。
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
タグ ヘルパーとしてビュー コンポーネントを呼び出す
ASP.NET Core 1.1 以降の場合は、タグ ヘルパーとしてビュー コンポーネントを呼び出すことができます。
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
タグ ヘルパーのパスカル ケースのクラスとメソッドのパラメーターは、それぞれケバブ ケースに変換されます。 ビュー コンポーネントを呼び出すタグ ヘルパーでは、<vc></vc>
要素を使用します。 ビュー コンポーネントは、次のように指定されます。
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
ビュー コンポーネントをタグ ヘルパーとして使用するには、@addTagHelper
ディレクティブを使用して、ビュー コンポーネントを含むアセンブリを登録します。 ビュー コンポーネントが呼び出された MyWebApp
アセンブリ内にある場合は、ファイルに次のディレクティブを _ViewImports.cshtml
追加します。
@addTagHelper *, MyWebApp
ビュー コンポーネントを参照する任意のファイルへのタグ ヘルパーとして、ビュー コンポーネントを登録できます。 タグ ヘルパーを登録する方法の詳細については、「Managing Tag Helper Scope」 (タグ ヘルパーのスコープの管理) を参照してください。
このチュートリアルで使用される InvokeAsync
メソッドは、次のとおりです。
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
タグ ヘルパーのマークアップでは、次のようになります。
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
上記のサンプルでは、PriorityList
ビュー コンポーネントは priority-list
になります。 ビュー コンポーネントに対するパラメーターは、ケバブ ケースの属性として渡されます。
ビュー コンポーネントをコントローラーから直接呼び出す
通常、ビュー コンポーネントはビューから呼び出されますが、コントローラー メソッドから直接呼び出すことができます。 ビュー コンポーネントでコントローラーなどのエンドポイントを定義しないときに、ViewComponentResult
のコンテンツを返すコントローラー アクションを簡単に実装できます。
この例では、ビュー コンポーネントは、コントローラーから直接呼び出されます。
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
チュートリアル: 単純なビュー コンポーネントの作成
スタート コードをダウンロード、ビルド、およびテストします。 これは、 [ToDo] 項目のリストを表示する ToDo
コントローラーを備えた、単純なプロジェクトです。
ViewComponent クラスの追加
ViewComponents フォルダーを作成して、次の PriorityListViewComponent
クラスを追加します。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
コードに関する注意事項
ビュー コンポーネント クラスは、プロジェクト内の任意のフォルダーに含めることができます。
クラス名 PriorityListViewComponent はサフィックス ViewComponent で終わるため、ランタイムはビューからクラス コンポーネントを参照するときに文字列
PriorityList
を使用します。[ViewComponent]
属性では、ビュー コンポーネントを参照するために使用する名前を変更できます。 たとえば、次の属性を使用してクラスに名前XYZ
をViewComponent
付けた可能性があります。[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
前のコードの属性は
[ViewComponent]
、ビュー コンポーネント セレクターに使用を指示します。- コンポーネントに関連付けられているビューを検索するときの名前
PriorityList
- ビューからクラス コンポーネントを参照するときの文字列 "PriorityList" です。
- コンポーネントに関連付けられているビューを検索するときの名前
コンポーネントでは、依存性の注入を使用して、データ コンテキストを利用できるようにします。
InvokeAsync
ではビューから呼び出すことができるメソッドを表示し、任意の数の引数を取得できます。InvokeAsync
メソッドでは、isDone
とmaxPriority
パラメーターを満たすToDo
項目のセットを返します。
ビュー コンポーネント Razor ビューの作成
Views/Shared/Components フォルダーを作成します。 このフォルダーには名前を付ける
Components
必要があります。Views/Shared/Components/PriorityList フォルダーを作成します。 このフォルダー名は、ビュー コンポーネント クラスの名前、または (規則に従い、クラス名に ViewComponent サフィックスを使用した場合は) サフィックスを差し引いたクラスの名前に一致する必要があります。
ViewComponent
属性を使用した場合は、クラス名は属性の指定に一致する必要があります。ビューを作成します
Views/Shared/Components/PriorityList/Default.cshtml
Razor 。@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Razor ビューでは、
TodoItem
のリストを取得してそれらを表示します。 ビュー コンポーネントのInvokeAsync
メソッドで (サンプルのように) ビューの名前を渡さない場合、Default が規則によってビュー名に使用されます。 このチュートリアルの後半で、ビューの名前を渡す方法について示します。 特定のコントローラーの既定のスタイルをオーバーライドするには、コントローラーに固有のビュー フォルダー (例: Views/ToDo/Components/PriorityList/Default.cshtml) にビューを追加します。ビュー コンポーネントがコントローラー固有の場合は、コントローラー固有のフォルダー (
Views/ToDo/Components/PriorityList/Default.cshtml
) に追加できます。div
優先度リスト コンポーネントの呼び出しを含むファイルの下部にViews/ToDo/index.cshtml
追加します。</table> <div> @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false }) </div>
@await Component.InvokeAsync
マークアップは、ビュー コンポーネントを呼び出すための構文を示します。 最初の引数は、呼び出す必要があるコンポーネントの名前です。 後続のパラメーターは、そのコンポーネントに渡されます。 InvokeAsync
では、任意の数の引数を取得できます。
アプリをテストします。 次の画像は、[ToDo] リストと優先順位の項目を示します。
また、コントローラーから直接ビュー コンポーネントを呼び出すこともできます。
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
ビュー名を指定する
複雑なビュー コンポーネントでは、いくつかの条件下で、既定以外のビューを指定する必要がある場合があります。 次のコードは、メソッドから "PVC" ビューを指定する方法を InvokeAsync
示しています。 PriorityListViewComponent
クラスで InvokeAsync
メソッドを更新します。
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
ファイルを Views/Shared/Components/PriorityList/Default.cshtml
名前付きの Views/Shared/Components/PriorityList/PVC.cshtml
ビューにコピーします。 PVC ビューが使用されていることを示すために、見出しを追加します。
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
以下を更新します。Views/ToDo/Index.cshtml
:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
アプリを実行して、PVC ビューを確認します。
PVC ビューがレンダリングされない場合は、4 以上の優先順位でビュー コンポーネントを呼び出していることを確認します。
ビューのパスを調べる
優先順位ビューが返されないように、優先順位パラメーターを 3 以下に変更します。
に一時的に名前を変更します
Views/ToDo/Components/PriorityList/Default.cshtml
1Default.cshtml
。アプリをテストすると、次のエラーが表示されます。
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml EnsureSuccessful
Views/ToDo/Components/PriorityList/1Default.cshtml
をViews/Shared/Components/PriorityList/Default.cshtml
にコピーします。[Shared] の [ToDo] ビュー コンポーネントのビューにマークアップを追加して、そのビューが [Shared] フォルダーからのものであることを示します。
[Shared] コンポーネント ビューをテストします。
ハードコーディングされた文字列の回避
コンパイル時間の安全性を確保する必要がある場合は、ハードコーディングされたビュー コンポーネント名をクラス名に置き換えることができます。 "ViewComponent" サフィックスのないビュー コンポーネントを作成します。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
using
ステートメントをお使いの Razor ビュー ファイルに追加して、nameof
演算子を使用します。
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo nameof</h2>
<!-- Markup removed for brevity. -->
<div>
@*
Note:
To use the below line, you need to #define no_suffix in ViewComponents/PriorityList.cs or it won't compile.
By doing so it will cause a problem to index as there will be multiple viewcomponents
with the same name after the compiler removes the suffix "ViewComponent"
*@
@*@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })*@
</div>
CLR 型を受け取る Component.InvokeAsync
メソッドのオーバーロードを使用できます。 この場合は、typeof
演算子を使用することを忘れないでください。
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo typeof</h2>
<!-- Markup removed for brevity. -->
<div>
@await Component.InvokeAsync(typeof(PriorityListViewComponent), new { maxPriority = 4, isDone = true })
</div>
同期作業を実行する
非同期作業を実行する必要がない場合は、フレームワークで同期 Invoke
メソッドの呼び出しが処理されます。 次のメソッドでは同期 Invoke
ビュー コンポーネントを作成します。
public class PriorityList : ViewComponent
{
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var items = new List<string> { $"maxPriority: {maxPriority}", $"isDone: {isDone}" };
return View(items);
}
}
ビュー コンポーネントのRazorファイルには、メソッド (Views/Home/Components/PriorityList/Default.cshtml
) に渡される文字列がInvoke
一覧表示されます。
@model List<string>
<h3>Priority Items</h3>
<ul>
@foreach (var item in Model)
{
<li>@item</li>
}
</ul>
ビュー コンポーネントは、次のいずれかの方法を Razor 使用してファイル (たとえば Views/Home/Index.cshtml
) で呼び出されます。
IViewComponentHelper の方法を使用するには、Component.InvokeAsync
を呼び出します。
@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })
タグ ヘルパーを使用するには、@addTagHelper
ディレクティブを使用して、ビュー コンポーネントを含むアセンブリを登録します (ビュー コンポーネントは、MyWebApp
と呼ばれるアセンブリ内にあります)。
@addTagHelper *, MyWebApp
Razor マークアップ ファイルでビュー コンポーネントのタグ ヘルパーを使用します。
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
PriorityList.Invoke
のメソッド署名は同期的ですが、Razor ではマークアップ ファイルで Component.InvokeAsync
を使用してメソッドを見つけて呼び出します。
ビュー コンポーネントのすべてのパラメーターが必要
ビュー コンポーネントの各パラメーターは、必須の属性です。 こちらの GitHub のイシューを参照してください。 いずれかのパラメーターを省略した場合は、次の手順を実行します。
InvokeAsync
メソッドのシグネチャが一致しないため、メソッドが実行されません。- ViewComponent がマークアップをレンダリングしません。
- エラーがスローされません。