ASP.NET8 ビュー コンポーネントを作成する方法は、一般的なパーティル ビューよりも強力なコンポーネントアーキテクチャ形式です。
ASP.NET8 ビュー コンポーネントを作成する方法は、一般的なパーティル ビューよりも強力なコンポーネントアーキテクチャ形式です。ASP.NET8 ビュー コンポーネントは、パーティル ビューよりも強力です。
簡単に言うと、ASP.NET8 ビューコンポーネントは Partial-Views に似ていますが、より高いレベルのコンポーネント化と機能のカプセル化を可能にします。
ASP.NET8 ビューコンポーネントは、再利用可能なコンポーネントを作成するために設計されており、ビュー/レンダリング機能があり、通常のパーティルビューよりも複雑です。
主な優位性 overASP.NETについてPart-Views は、View-Components が aサーバー側で実行されているコンポーネント部分また、データベースアクセスレイヤー(例えばEF)などのすべてのアプリケーションアーキテクチャのメカニズムに、ホストページから独立してアクセスできます. That allows quite elaborate and complex processing that can be done and componentized into a reusable form.
サーバー側で実行されているコンポーネント部分ASP.NET8 ビュー・コンポーネントは、呼び出し方法(ホストページまたはコントローラさえ直接)からパラメータを受け取りますが、HTTP リクエストではなく、もちろん、HttpRequest をパラメータとして受け取るビュー・コンポーネントの作成を妨げるものはありません。
コンポーネント inASP.NETについてコアは記事(1)でよく定義されていますが、私はここですべてを繰り返すつもりはありません。計画は、ビューコンポーネントが通常どのように使用されるかについて、動作するC#サンプルコード(「ファースト」)を提供することです。
2.最終結果
ここでは最終結果を示します。そこにASP.NET8ホストページは2つのコンポーネントと4つの呼び出しが画像に示されています。コンポーネントは彼らがどこにいるかを示すために意図的にカラーされます。実際のアプリでは、もちろん、カラーは使用されません。
-
Div-0. Control in Host ASP.NET8 page
-
Div-1. View-Component-1 CustomerSearch, which is Async component, invoked with a method
-
Div-2. View-Component-1 CustomerSearch, which is Async component, invoked with Tag Helper
-
Div-3. View-Component-2 CustomerSearch2, which is Sync component, invoked with a method
-
Div-4. View-Component-2 CustomerSearch2, which is Sync component, invoked with Tag Helper
3.この例のソースコード
ソースコードはよくコメントされており、自己説明でなければなりません。
3.1 C# 部分
//HomeController.cs=========================================
namespace Example1.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
//in this action we are testing the ViewComponent
public IActionResult Test1(Test1_ViewModel model)
{
return View(model);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
// CustomersSearchViewComponent_Model.cs ==========================
namespace Example1.ViewComponents.Models
{
public class CustomersSearchViewComponent_Model
{
public string? Parameter1String { get; set; } = null;
public int? Parameter2Int { get; set; } = null;
public string? IdOfTargetInputField { get; set; } = null;
}
}
// CustomersSearchViewComponent_ViewModel.cs ==========================
namespace Example1.ViewComponents.Models
{
public class CustomersSearchViewComponent_ViewModel
{
public string? Parameter1String { get; set; } = null;
public int? Parameter2Int { get; set; } = null;
public string? IdOfTargetInputField { get; set; } = null;
//this should come from DB in real application
public SelectList? ListOfCustomers { get; set; }
}
}
//CustomersSearch2ViewComponent.cs===================================================
namespace Example1.ViewComponents
{
//it should inherit from ViewComponent class
//this is Sync version of ViewComponent
public class CustomersSearch2ViewComponent : ViewComponent
{
private readonly ILogger<CustomersSearch2ViewComponent>? _logger;
// We are testing Dependency Injection (DI) to inject the logger
public CustomersSearch2ViewComponent(ILogger<CustomersSearch2ViewComponent> logger)
{
//note how useful is this, we are passing in this constructor
//into view-component objects that are part of app DI container
//you can pass here any form of reference to DataBase, for example
//like EF DbContext or similar
_logger = logger;
}
//The Invoke method for the View component
public IViewComponentResult Invoke(
CustomersSearchViewComponent_Model? model = null
)
{
//this is neat, this parameters in CustomersSearchViewComponent_Model
//are passed to the view-component from host form
{
//testing that DI worked - logger
string methodName = $"Type: {System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType?.FullName}, " +
$"Method: InvokeAsync; ";
_logger?.LogWarning(methodName);
}
//preparing view-model
CustomersSearchViewComponent_ViewModel viewModel = new();
viewModel.Parameter1String = model?.Parameter1String;
viewModel.Parameter2Int = model?.Parameter2Int;
viewModel.IdOfTargetInputField = model?.IdOfTargetInputField;
{
//this should come from DB in real application
SelectList list1 = new SelectList
(new List<SelectListItem>
{
new SelectListItem
{
Text = "John - 111",
Value = "111"
},
new SelectListItem
{
Text = "Mark - 222",
Value = "222"
},
new SelectListItem
{
Text = "Novak - 333",
Value = "333"
},
}, "Value", "Text");
viewModel.ListOfCustomers = list1;
}
//now render component view
return View("Default", viewModel);
}
}
}
//CustomersSearchViewComponent.cs===================================================
namespace Example1.ViewComponents
{
//it should inherit from ViewComponent class
//this is Async version of ViewComponent
public class CustomersSearchViewComponent : ViewComponent
{
private readonly ILogger<CustomersSearchViewComponent>? _logger;
// We are testing Dependency Injection (DI) to inject the logger
public CustomersSearchViewComponent(ILogger<CustomersSearchViewComponent> logger)
{
//note how useful is this, we are passing in this constructor
//into view-component objects that are part of app DI container
//you can pass here any form of reference to DataBase, for example
//like EF DbContext or similar
_logger = logger;
}
//The Invoke method for the View component
public async Task<IViewComponentResult> InvokeAsync(
CustomersSearchViewComponent_Model? model=null
)
{
//this is neat, this parameters in CustomersSearchViewComponent_Model
//are passed to the view-component from host form
{
//testing that DI worked - logger
string methodName = $"Type: {System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType?.FullName}, " +
$"Method: InvokeAsync; ";
_logger?.LogWarning(methodName);
}
await Task.Delay(0); // Simulate some async work
//preparing view-model
CustomersSearchViewComponent_ViewModel viewModel = new();
viewModel.Parameter1String = model?.Parameter1String;
viewModel.Parameter2Int = model?.Parameter2Int;
viewModel.IdOfTargetInputField = model?.IdOfTargetInputField;
{
//this should come from DB in real application
SelectList list1 = new SelectList
(new List<SelectListItem>
{
new SelectListItem
{
Text = "John - 111",
Value = "111"
},
new SelectListItem
{
Text = "Mark - 222",
Value = "222"
},
new SelectListItem
{
Text = "Novak - 333",
Value = "333"
},
}, "Value", "Text");
viewModel.ListOfCustomers= list1;
}
//now render component view
return View("Default",viewModel);
}
}
}
3.2 Razor (.cshtml) パーツ
<!--Test1.cshtml --------------------------------------------------->
@using Example1.Models.Home;
@using Example1.ViewComponents;
@using Example1.ViewComponents.Models;
@using Example1
@using Example1.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Example1
@addTagHelper *, Example1.TagHelpers
@model Test1_ViewModel
@{
ViewData["Title"] = "Test1";
<!--Title --------------------------------------------------->
<h5 class="bg-primary text-left p-1 mt-1">
<span class="d-inline-block ms-2">
@ViewData["Title"]
</span>
</h5>
<!-- Flexbox row1 -->
<div class="d-flex" style="width:1100px">
<!-- Div 0-------------------------------------------------->
<div class="m-3 p-3">
<fieldset class="border rounded-3 p-3 bg-light shadow" style="width:500px">
<legend class="float-none w-auto px-3 border bg-light rounded-3 ">
Div - 0
</legend>
<!-- Form ----------------------------------------------------------------- -->
<form id="form1" method="post" class="row">
<div class="form-group">
<label asp-for="ContractOwnerCustomer">
Customer Id
</label>
<input id="ContractOwnerCustomerId" class="form-control" asp-for="ContractOwnerCustomer" />
</div>
</form>
<hr />
<!--Buttons ----------------------------------------------------- -->
<div>
<button type="submit" form="form1" class="btn btn-primary mt-3 me-2 float-end"
href=''>
Submit
</button>
</div>
</fieldset>
</div>
</div>
<!-- Flexbox row2 -->
<div class="d-flex" style="width:1100px">
<!-- Div 1----------------------------------------------- -->
<div class="m-3 p-3">
<h5 class="bg-secondary text-center p-1">
Div1 - CustomersSearch, Async, invoked with method
</h5>
@{
CustomersSearchViewComponent_Model myModel1 = new CustomersSearchViewComponent_Model();
myModel1.Parameter1String = "Div1-Async, invoked with method";
myModel1.Parameter2Int = 11111;
myModel1.IdOfTargetInputField = "ContractOwnerCustomerId";
//so, here we are using the ViewComponent
@await Component.InvokeAsync("CustomersSearch", new
{
model = myModel1,
}) ;
}
</div>
<!-- Div 2----------------------------------------------- -->
<div class="m-3 p-3">
<h5 class="bg-secondary text-center p-1">
Div2 - CustomersSearch, Async, invoked with Tag Helper
</h5>
@{
CustomersSearchViewComponent_Model myModel2 = new CustomersSearchViewComponent_Model();
myModel2.Parameter1String = "Div2-Async, invoked with Tag Helper";
myModel2.Parameter2Int = 22222;
myModel2.IdOfTargetInputField = "ContractOwnerCustomerId";
}
<vc:customers-search model=myModel2>
</vc:customers-search>
</div>
</div>
<!-- Flexbox row3-->
<div class="d-flex" style="width:1100px">
<!-- Div 3----------------------------------------------- -->
<div class="m-3 p-3">
<h5 class="bg-secondary text-center p-1">
Div3 - CustomersSearch2, Sync, invoked with method
</h5>
@{
CustomersSearchViewComponent_Model myModel3 = new CustomersSearchViewComponent_Model();
myModel1.Parameter1String = "Div3-Sync, invoked with method";
myModel1.Parameter2Int = 33333;
myModel1.IdOfTargetInputField = "ContractOwnerCustomerId";
//so, here we are using the ViewComponent
//it looks strange, Sync component invoked with async method
//but they want it this way
@await Component.InvokeAsync("CustomersSearch2", new
{
model = myModel1,
}) ;
}
</div>
<!-- Div 4----------------------------------------------- -->
<div class="m-3 p-3">
<h5 class="bg-secondary text-center p-1">
Div4 - CustomersSearch2, Sync, invoked with Tag Helper
</h5>
@{
CustomersSearchViewComponent_Model myModel4 = new CustomersSearchViewComponent_Model();
myModel2.Parameter1String = "Div4- Sync, invoked with Tag Helper";
myModel2.Parameter2Int = 44444;
myModel2.IdOfTargetInputField = "ContractOwnerCustomerId";
}
<vc:customers-search2 model=myModel2>
</vc:customers-search2>
</div>
<!-- ----------------------------------------------- -->
</div>
}
<!--CustomersSearch\Default.cshtml -------------------------------->
@using Example1.ViewComponents.Models
@model CustomersSearchViewComponent_ViewModel
<!--Visually, this div (color bg-info) is the component--->
<div id="ViewComponents1" class="bg-info p-3" style="width:400px">
<!--Title --------------------------------------------------->
<h5 class="bg-primary text-center p-1 m-3">
CustomersSearch - Async ViewComponent
</h5>
<p>
Proof-of-concept, parameter from Host Form
<br/> Parameter1String: @Model.Parameter1String
</p>
<p>
Proof-of-concept, parameter from Host Form
<br /> Parameter2Int: @Model.Parameter2Int
</p>
<fieldset class="border rounded-3 p-3 m-2 shadow">
<label>
Proof-of-concept, list of customers from DB
</label>
<select id="customerSelect2" class="form-select"
asp-items="@Model.ListOfCustomers">
</select>
<a class="btn btn-secondary mt-3 float-end"
onclick="copyInputTextTo(this)">
Copy Selected Customer ID to Form
</a>
</fieldset>
</div> <!-- End of <div id="ViewComponents1" -->
<script>
// This function will export selection value from the ViewComponent
// to the main form and copy it to the input field
function copyInputTextTo(anchor) {
var root = anchor.closest('fieldset');
var target = document.getElementById("@Model.IdOfTargetInputField");
var source = root.querySelector('#customerSelect2') ;
if (source && target) {
target.value = source.value;
}
return false;
}
</script>
<!--CustomersSearch2\Default.cshtml -------------------------------->
@using Example1.ViewComponents.Models
@model CustomersSearchViewComponent_ViewModel
<!--Visually, this div (color bg-warning) is the component--->
<div id="ViewComponents1" class="bg-warning p-3" style="width:400px">
<!--Title --------------------------------------------------->
<h5 class="bg-primary text-center p-1 m-3">
CustomersSearch2 - Sync ViewComponent
</h5>
<p>
Proof-of-concept, parameter from Host Form
<br /> Parameter1String: @Model.Parameter1String
</p>
<p>
Proof-of-concept, parameter from Host Form
<br /> Parameter2Int: @Model.Parameter2Int
</p>
<fieldset class="border rounded-3 p-3 m-2 shadow">
<label>
Proof-of-concept, list of customers from DB
</label>
<select id="customerSelect2" class="form-select"
asp-items="@Model.ListOfCustomers">
</select>
<a class="btn btn-secondary mt-3 float-end"
onclick="copyInputTextTo(this)">
Copy Selected Customer ID to Form
</a>
</fieldset>
</div> <!-- End of <div id="ViewComponents1" -->
<script>
// This function will export selection value from the ViewComponent
// to the main form and copy it to the input field
function copyInputTextTo(anchor) {
var root = anchor.closest('fieldset');
var target = document.getElementById("@Model.IdOfTargetInputField");
var source = root.querySelector('#customerSelect2') ;
if (source && target) {
target.value = source.value;
}
return false;
}
</script>
3.3 プロジェクト内のファイルの位置
4.結論
ASP.NET8 のコンポーネントの表示は、より高い形式のコンポーネントアーキテクチャであり、私はそれを実用的に見つけました。それらに慣れ、それらを作成 / 使用する方法を学ぶにはしばらくかかりますが、彼らは確実に経験豊富な誰にでも役に立ちます。ASP.NETについてプログラミング
5 参照
[1] ASP.NET Core でコンポーネントを表示
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-9.0
[2] ASP.NET Core MVC のコンポーネントを表示する
https://dotnettutorials.net/lesson/view-components-in-asp-net-core-mvc/