본문 바로가기
ASP.NET Core

ASP.NET Core]Partial Views VS View Components

by Fastlane 2022. 1. 7.
728x90
반응형

View Components는 ASP.NET Core MVC에서 새롭게 소개된 feature다. partial view와 비슷하지만, 더 강력하다. View Components는 model binding을 사용하지 않고, 호출 시 제공받은 data만 사용한다. partial view를 사용하기에 로직이 너무 복잡할 때 사용한다. 가장 중요한 것은, dependency injection을 사용한다는 것이다. 

 

  • SOC(Separation Of Concerns)를 지원한다. 
  • parameter와 고유 business logic을 가진다. 
  • Layer Page에서 실행된다. 
  • chunk만 렌더링 한다.  
  • filters는 사용할 수 없다. 
  • request로 호출할 수 없다. 보통 view에서 호출된다. 

View Component 만들기

아래 두 가지 방식으로 View Component를 선언한다. class명은 ViewComponent로 끝난다. 

 public class EmployeeViewComponent: ViewComponent
 { }
 
 [ViewComponent(Name = "Employee")]
 public class EmployeeInfo: ViewComponent
 {}

위 class 파일은 Shared폴더에 저장한다. 

view component class에서 우리는 한 메서도를 반드시 정의해야 한다. 

 public async Task InvokeAsync(string EmployeeCode) {
 Employee objEmployee;
 //...retrieve or build Employee object for a specified Employee
 return View(objEmployee);
 }

View Component 호출하기

이제 @Component.InvokeAsync()함수를 사용해서 view 어디에서든 view component를 호출할 수 있다. 

 @Component.InvokeAsync("EmployeeViewComponent",<anonomous type containing params>)

parameter는 InvokeAsync함수로 전달된다. 

@await Component.InvokeAsync("EmployeeViewComponent", "A001")

View Components는 보통 views에서 호출되지만, controller에서도 가능하다. 

 public IActionResult EmployeeView()
 {
 return ViewComponent("EmployeeViewComponent", "A001");
 }

IViewComponentResult, Task<IViewComponentResult>를 반환한다. 

간단한 View Component 만들어보기

PriorityListViewComponents.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using VUE.Models;

namespace VUE.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);

            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);
        }
        private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
        {
            return db.ToDo.Where(x => x.IsDone == isDone &&
                                 x.Priority <= maxPriority).ToListAsync();
        }
    }
}

Index.cshtml

@using VUE.Models
@model IEnumerable<TodoItem>

@{
   
    Layout = null; 
}

<h2>ToDo</h2>

<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.IsDone)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Priority)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.IsDone)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Priority)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
        </tr>
    }
</table>
<div>
    @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false })
</div>

Default.cshtml

@model IEnumerable<VUE.Models.TodoItem>

<h3>Priority Items</h3>
<ul>
    @foreach (var todo in Model)
    {
        <li>@todo.Name</li>
    }
</ul>

PVC.cshtml

@model IEnumerable<VUE.Models.TodoItem>

<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
    @foreach (var todo in Model)
    {
        <li>@todo.Name</li>
    }
</ul>

ToDoController.cs

using Microsoft.AspNetCore.Mvc;
using VUE.Models;

namespace VUE.Controllers
{
    public class ToDoController : Controller
    {
        private readonly ToDoContext _ToDoContext;

        public ToDoController(ToDoContext context)
        {
            _ToDoContext = context;

            // EnsureCreated() is used to call OnModelCreating for In-Memory databases as migration is not possible
            // see: https://github.com/aspnet/EntityFrameworkCore/issues/11666 
            _ToDoContext.Database.EnsureCreated();
        }

        public IActionResult Index()
        {
            var model = _ToDoContext.ToDo.ToList();
            return View(model);
        }
        #region snippet_IndexVC
        public IActionResult IndexVC()
        {
            return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
        }
        #endregion
    }
}

ToDoContext.cs

using Microsoft.EntityFrameworkCore;

namespace VUE.Models
{
    public class ToDoContext : DbContext
    {
        public ToDoContext(DbContextOptions<ToDoContext> options)
                : base(options)
        {
        }
        public DbSet<TodoItem> ToDo { get; set; }

        //The below is used to seeding the DB
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            for (int i = 0; i < 9; i++)
            {
                modelBuilder.Entity<TodoItem>().HasData(
                   new TodoItem
                   {
                       Id = i + 1,
                       IsDone = i % 3 == 0,
                       Name = "Task " + (i + 1),
                       Priority = i % 5 + 1
                   });
            }
        }
    }
}

ToDoItem.cs

using System.ComponentModel.DataAnnotations;

namespace VUE.Models
{
    public class TodoItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Priority { get; set; }
        public bool IsDone { get; set; }
    }
}

Program.cs

builder.Services.AddControllersWithViews();

builder.Services.AddDbContext<ToDoContext>(options =>
        options.UseInMemoryDatabase("db"));

var app = builder.Build();

728x90
반응형

댓글