ASP.NET8 View Components Set New Bar for Web UI Reusability オリジナルタイトル

Mark Pelf23m2025/05/23
Read on Terminal Reader

長すぎる; 読むには

ASP.NET8 ビュー コンポーネントを作成する方法は、一般的なパーティル ビューよりも強力なコンポーネントアーキテクチャ形式です。
featured image - ASP.NET8 View Components Set New Bar for Web UI Reusability オリジナルタイトル
Mark Pelf HackerNoon profile picture
0-item

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/

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks