Comment créer les composants d'affichage ASP.NET8, qui sont une forme d'architecture de composants plus puissante que les affichages partiels populaires.
Comment créer les composants d'affichage ASP.NET8, qui sont une forme d'architecture de composants plus puissante que les affichages partiels populaires.ASP.NET8 Affichage-Composants sont plus puissants que les Affichages partiels
En termes simples, les composants d'affichage ASP.NET8 sont similaires à ceux d'affichage partiel, mais permettent un niveau plus élevé de composition et d'encapsulation des fonctionnalités.
Les View-Components ASP.NET8 sont destinés à la création de composants réutilisables qui ont la fonctionnalité View/Render et dont la complexité est supérieure à celle des Part-Views normaux.
Un avantage majeur surpar ASP.NETParticular-Views est que les View-Components ont unpartie du composant qui est du côté du serveur exécutéet peut accéder à tous les mécanismes de l'architecture d'application, tels que Database Access Layer (par exemple EF) indépendamment de la page hôte où ils sont hébergés.
partie du composant qui est du côté du serveur exécutéASP.NET8 View-Components reçoit des paramètres de la méthode d'appel (page hôte ou même contrôleur directement) et non la demande HTTP. Mais, bien sûr, rien n'empêche la création de View-Components qui reçoivent HttpRequest comme un paramètre qui sera explicitement transmis au composant.
Voir les composants enpar ASP.NETLes noyaux sont bien définis dans l'article [1], et je ne vais pas le répéter ici. Le plan est de fournir un code d'échantillon de travail C# ("Premier") sur la façon dont les composants de vue peuvent généralement être utilisés. code réutilisable avec un exemple simple est montré ci-dessous. J'ai ajouté une quantité décente de commentaires, il devrait donc être explicatif de la façon dont ils fonctionnent.
2 - Résultat final
Ici nous montrons le résultat final. Il y a ASP.NET8 page hôte a 2 composants et 4 invocations montrées sur l'image. Les composants sont colorés délibérément pour montrer où ils sont. Dans une application réelle, bien sûr, la coloration ne serait pas utilisée. Voici ce que cet exemple montre:
-
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
Le code source pour cet exemple
Le code source est bien commenté, et il devrait être auto-explicatif.
4.1 Partie 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 Partie de 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 Emplacement des fichiers dans le projet
4 - Conclusion
Afficher les composants dans ASP.NET8 est une forme supérieure de l'architecture de composants, et j'ai trouvé pratique. Il faut du temps pour s'y habituer et apprendre à les créer / les utiliser, mais ils sont certainement utiles à toute personne expérimentéepar ASP.NETLes programmes.
5 Références
[1] Afficher les composants dans ASP.NET Core
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-9.0
[2] Afficher les composants dans ASP.NET Core MVC
https://dotnettutorials.net/lesson/view-components-in-asp-net-core-mvc/