32. 뷰 컴포넌트
ASP.NET Core에서 새롭게 도입된 뷰 컴포넌트는 UI와 데이터를 묶어서 뷰 페이지의 원하는 곳에서 출력해주는 기능을 제공합니다.
32.1. 소개
ASP.NET Core에서 뷰 컴포넌트(View Component)란 UI와 Data를 묶어서 뷰 페이지에 출력해 주는 컴포넌트를 말합니다. 기존 웹 폼의 서버 컨트롤, MVC의 부분 뷰(Partial View)와 비슷한 개념입니다. 뷰 컴포넌트는 한 번 만들어 놓고, 여러 개의 뷰 페이지에서 호출해서 사용할 수 있습니다.
- 재 사용
- 특정 기능을 하나의 조각으로 묶어서 관리
그림: 1 뷰 컴포넌트
뷰 컴포넌트는 동적인 메뉴, 로그인 패널, 쇼핑 카트, 최근 글 리스트 등 부분 페이지를 구현하는데 유용합니다.
코드조각: 뷰 컴포넌트 호출
<div>
@await Component.InvokeAsync(“NoticeWidget”)
</div>
참고: 뷰 컴포넌트, 부분 뷰, 태그 헬퍼 중 어떤 것 사용?
특별히 어떤 것이 더 좋다라는 것은 의미가 없을 것 같습니다. 뷰 컴포넌트, 부분 뷰, 태그 헬퍼의 3가지로 동일한 기능을 구현할 수 있습니다.
32.2. ViewComponent 클래스
모든 뷰 컴포넌트는 ViewComponent
클래스로부터 상속을 받습니다. MVC 컨트롤러 클래스와 비슷하게 뷰 컴포넌트는 ViewComponent
접미사로 끝납니다.
32.3. 뷰 컴포넌트 경로
뷰 페이지에서 호출되는 뷰 컴포넌트는 다음 경로에서 찾습니다. 기본 뷰 이름은 Default.cshtml 파일입니다.
- Views/<컨트롤러 이름>/Components/<뷰 컴포넌트 이름>/<뷰 이름>
- Views/Shared/Components/<뷰 컴포넌트 이름>/<뷰 이름>
<참고> 자식 액션의 경로와 뷰 컴포넌트의 경로 자식 액션 Views/Shared/{뷰이름} 뷰 컴포넌트 Views/Shared/Components/{컴포넌트이름}/{뷰이름} Views/<컨트롤러이름>/Components/{컴포넌트이름}/{뷰이름}
32.4. 뷰 컴포넌트 호출
@Component.InvokeAsync(“뷰 컴포넌트 이름”, <익명 형식의 매개변수 리스트>)
32.5 컨트롤러에서 직접 뷰 컴포넌트 호출 뷰 컴포넌트는 이름처럼 뷰에서 호출하여 사용하는 기능이지만, 컨트롤러에서 ViewComponent() 메서드를 통해 직접 호출할 수도 있습니다.
32.6 뷰 컴포넌트의 폴더 구조 ASP.NET Core에서 뷰 컴포넌트를 사용하려면 프로젝트 루트에 ViewComponents 폴더를 만들고 이곳에 ViewComponent 접미사를 사용하여 클래스 파일을 만듭니다. 이 뷰 컴포넌트에 대한 UI 페이지는 Shared 폴더에 Components 폴더를 만들고, 뷰 컴포넌트 이름으로 폴더를 만든 다음, 기본값으로 Default.cshtml 페이지를 만들어 이곳에 UI를 구성합니다. 다음은 Copyright 이름의 뷰 컴포넌트를 생성한 후의 프로젝트 구조입니다. 그림: 2 뷰 컴포넌트의 폴더 구조
뷰 컴포넌트 생성 코드 조각
DotNetNote\Components\TextMessages\AddTextMessageViewComponent.cs
public class AddTextMessageViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
public class AddTextMessageViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
return await Task.FromResult(View());
}
}```
## 32.7. [실습] ASP.NET Core에서 뷰 컴포넌트 만들기
### 32.7.1. 소개
ASP.NET Core에서 Razor 구문을 담고 있는 UI와 데이터를 묶어서 간단한 조각(부분) 페이지를 만들어 낼 수 있는 단위를 뷰 컴포넌트라고 합니다. 최소한의 절차로 뷰 컴포넌트를 만드는 과정을 실습해보겠습니다.
### 32.7.2. 따라하기 1: 초간단 뷰 컴포넌트 만들기
동영상 강의:
31_01_뷰 컴포넌트_Copyright 정보를 출력하는 뷰 컴포넌트 만들기(Data와 UI를 갖는 뷰 컴포넌트)
(1) Visual Studio를 열고 C:\ASP.NET\DotNetNote 프로젝트를 실행합니다.
(2) DotNetNote 프로젝트의 루트에 ViewComponents 이름으로 폴더가 있는지 확인합니다. ASP.NET Core에서는 이 폴더에 뷰 컴포넌트 클래스를 넣어 놓는다. ViewComponents 폴더에 *CopyrightViewComponent.cs* 이름으로 클래스를 생성하고, 다음과 같이 ViewComponent 클래스로부터 상속받아 Invoke() 메서드를 구현합니다.
```csharp
/ViewComponents/CopyrightViewComponent.cs
using Microsoft.AspNetCore.Mvc;
using System;
namespace DotNetNote.ViewComponents
{
/// <summary>
/// Copyright 뷰 컴포넌트
/// </summary>
public class CopyrightViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
// 초 단위로 짝수일 때와 홀수일 때 서로 다른 뷰 출력
string viewName = "Default";
if (DateTime.Now.Second % 2 == 0)
{
viewName = "Details";
}
return View(viewName);
}
}
}
(3) Views/Shared 폴더에 Components 폴더가 있는지 확인하고 만약 새롭게 프로젝트를 만들어서 연습한다면 Components 폴더를 새롭게 생성합니다. 이곳에 뷰 컴포넌트 이름인 Copyright 이름으로 폴더를 생성하고, Default.cshtml로 뷰 페이지를 만든 다음 다음과 같이 코드를 작성합니다.
코드: /Views/Shared/Components/Copyright/Default.cshtml
<div class="text-center">
Copyright © @DateTime.Now.Year all right reserved.
</div>
뷰 컴포넌트의 뷰 페이지의 기본 이름은 Default.cshtml입니다.
(4) 같은 경로에 Details.cshtml 뷰 페이지를 추가한 후 다음과 같이 코드를 작성합니다. 뷰 컴포넌트에서 서로 다른 뷰를 호출하는 걸 테스트하기 위해서 코드만 조금 바꾸었습니다.
/Views/Shared/Components/Copyright/Details.cshtml
<div class="text-center">
Copyright © @DateTime.Now.Year <em>DotNetNote</em> all right reserved.
</div>
(5) 뷰 컴포넌트를 테스트할 페이지를 작성합니다. Controllers 폴더에ViewComponentDemoController.cs 파일로 컨트롤러를 추가하고 다음과 같이 코드를 입력합니다.
/Controllers/ViewComponentDemoController.cs
using Microsoft.AspNetCore.Mvc;
namespace DotNetNote.Controllers
{
public class ViewComponentDemoController : Controller
{
public IActionResult Index()
{
return View();
}
/// <summary>
/// CopyrightViewComponent 출력 데모
/// </summary>
/// <returns></returns>
public IActionResult CopyrightDemo()
{
return View();
}
}
}
(6) Views 폴더에 컨트롤러 이름인 ViewComponentDemo로 폴더를 생성하고 CopyrightDemo.cshtml 이름으로 뷰 페이지를 작성 후 다음과 같이 뷰 컴포넌트를 호출하는 코드를 작성합니다. InvokeAsync 메서드가 비동기 메서드이므로 @await를 붙여서 호출해야 합니다.
/Views/ViewComponentDemo/CopyrightDemo.cshtml
@{
Layout = null;
}
<h3>Copyright 뷰 컴포넌트 호출</h3>
@await Component.InvokeAsync("Copyright")
(7) 현재 프로젝트를 시작 프로젝트로 설정하고, [Ctrl]+[F5]로 실행합니다. 웹 브라우저 경로에 /ViewComponentDemo/CopyrightDemo 경로를 요청하면 다음과 같이 출력됩니다. 그림: 3 Copyright 뷰 컴포넌트 호출
단순히 Copyright 문자열을 출력시키는 뷰 컴포넌트를 만들어 보았습니다. 간단한 예제를 살펴보았으니 다음에는 컬렉션 형태의 데이터를 받아서 UI를 꾸며주는 뷰 컴포넌트로 확장해보겠습니다.
전체 소스는 다음과 같습니다.
C:\DotNetNote6\DotNetNote\DotNetNote\DotNetNote\ViewComponents\CopyrightViewComponent.cs
namespace DotNetNote.ViewComponents;
/// <summary>
/// Copyright 뷰 컴포넌트
/// </summary>
public class CopyrightViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
// 초 단위로 짝수일 때와 홀수일 때 서로 다른 뷰 출력
string viewName = "Default";
if (DateTime.Now.Second % 2 == 0)
{
viewName = "Details";
}
return View(viewName);
}
}
C:\DotNetNote6\DotNetNote\DotNetNote\DotNetNote\Views\Shared\Components\Copyright\Default.cshtml
<div class="text-center">
Copyright © @DateTime.Now.Year all rights reserved.
</div>
C:\DotNetNote6\DotNetNote\DotNetNote\DotNetNote\Views\Shared\Components\Copyright\Details.cshtml
<div class="text-center">
Copyright © @DateTime.Now.Year <em>DotNetNote</em> all right reserved.
</div>
C:\DotNetNote6\DotNetNote\DotNetNote\DotNetNote\Views\Shared_Layout.cshtml
@await Component.InvokeAsync("Copyright")
32.7.3 따라하기 2: 데이터와 UI를 포함한 뷰 컴포넌트 만들기 1
(1) 이번에는 데이터를 사용하는 뷰 컴포넌트를 만듭니다. DotNetNote 프로젝트에 Models 폴더에 Tech.cs 파일로 모델 클래스인 Tech 클래스를 다음과 같이 작성합니다. 이 클래스의 내용은 Web API를 학습할 때 한 번 더 사용할 예정입니다.
/Models/Tech.cs
namespace DotNetNote.Models
{
/// <summary>
/// Teches 테이블과 일대일로 연결되는 클래스
/// </summary>
public class Tech
{
public int Id { get; set; }
public string Title { get; set; }
}
}
(2) 계속해서 새로운 뷰 컴포넌트를 만들어보겠습니다. DotNetNote 프로젝트의 ViewComponents 폴더에 TechListViewComponent.cs 이름으로 클래스 파일을 생성하고 다음과 같이 코드를 작성합니다. 뷰 페이지에 컬렉션 형태의 데이터를 던져주는 코드가 추가되었습니다. 이 부분 코드는 실제 데이터베이스를 사용해도 되지만, 뷰 컴포넌트 학습에 초점을 맞춰 List<T>
형태의 인 메모리 데이터베이스를 사용하였습니다.
/ViewComponents/TechListViewComponent.cs
using DotNetNote.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace DotNetNote.ViewComponents
{
public class TechListViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
var techLists = new List<Tech>() {
new Tech { Id = 1, Title = "ASP.NET Core" },
new Tech { Id = 2, Title = "Bootstrap" },
new Tech { Id = 3, Title = "C#" },
new Tech { Id = 4, Title = "Dapper" },
new Tech { Id = 5, Title = "Azure" },
new Tech { Id = 6, Title = "jQuery" },
new Tech { Id = 7, Title = "Angular" }
};
return View(techLists);
}
}
}
(3) Views 폴더의 Shared 폴더의 Components 폴더에 TechList 폴더를 생성합니다. Default.cshtml 뷰 페이지를 생성하고 다음과 같이 코드를 작성합니다. 컬렉션 형태의 데이터를 받아서 반복 구문을 통해 UI를 만들어낸다.
/Views/Shared/Components/TechList/Default.cshtml
@model List<DotNetNote.Models.Tech>
<ul>
@foreach (var t in Model)
{
<li>@t.Title</li>
}
</ul>
(4) TechList 뷰 컴포넌트를 테스트해보겠습니다. ViewComponentDemo 컨트롤러에 다음과 같이 TechListDemo 액션 메서드를 추가합니다.
/Controllers/ViewComponentDemoController.cs에 액션 메서드 추가
/// <summary>
/// TechListViewComponent 사용 데모
/// </summary>
/// <returns></returns>
public IActionResult TechListDemo()
{
return View();
}
(5) 마지막으로 TechListDemo.cshtml 뷰 페이지를 작성합니다. 뷰 컴포넌트를 호출하는 코드를 사용하여 TechList와 Copyright 뷰 컴포넌트를 호출합니다.
~/Views/ViewComponentDemo/TechListDemo.cshtml
@{
Layout = null;
}
<h3>현재 사이트에서 사용된 기술 리스트</h3>
@await Component.InvokeAsync("TechList")
@await Component.InvokeAsync("Copyright")
(6) 현재 프로젝트를 시작 프로젝트로 설정 후 [Ctrl]+[F5]로 실행합니다. 웹 브라우저에 /ViewComponentDemo/TechListDemo 경로를 요청하면 다음과 같이 출력됩니다. List<T>
형태로 저장된 문자열 데이터가 UI 코드와 섞여서 출력됩니다.
그림: 4 TechList 뷰 컴포넌트 실행
32.7.4 따라하기 3: 데이터와 UI를 포함한 뷰 컴포넌트 만들기 2
(1) 이번에는 즐겨찾기 사이트 또는 추천 사이트 리스트를 만들기 위한 뷰 컴포넌트를 만들어 보겠습니다. DotNetNote 프로젝트의 Models 폴더에 Site.cs 클래스 파일을 생성하고, 모델 클래스인 Site 클래스를 다음과 같이 작성합니다. 이 뷰 컴포넌트의 내용은 메인 페이지를 꾸밀 때 사용될 것입니다.
/Models/Site.cs
namespace DotNetNote.Models
{
/// <summary>
/// Site 모델 클래스 === Sites 테이블
/// </summary>
public class Site
{
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public string Description { get; set; }
}
}
(2) 계속해서 새로운 뷰 컴포넌트를 만들어 보겠습니다. DotNetNote 프로젝트의 ViewComponents 폴더에 SiteListViewComponent.cs 이름으로 클래스 파일을 생성하고 다음과 같이 코드를 작성합니다. TechList 뷰 컴포넌트와 마찬가지로 뷰 페이지에 컬렉션 형태의 데이터를 던져 주는 코드가 추가되었습니다.
/ViewComponents/SiteListViewComponent.cs
using DotNetNote.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace DotNetNote.ViewComponents
{
public class SiteListViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
var siteLists = new List<Site>() {
new Site { Id = 1, Title = "길벗출판사",
Url = "http://www.gilbut.co.kr",
Description = "ASP.NET Core 서적 출간" },
new Site { Id = 2, Title = "데브렉",
Url = "http://www.devlec.com",
Description = "DotNetNote 사이트 제작 관련 동영상 강의 제공" },
new Site { Id = 3, Title = "Taeyo.NET",
Url = "http://www.taeyo.net",
Description = "ASP.NET Core 강좌 제공" },
new Site { Id = 4, Title = "ASP.NET Korea User Group",
Url = "https://www.facebook.com/groups/AspxKorea/",
Description = "ASP.NET 한국 사용자 그룹" },
new Site { Id = 5, Title = "닷넷코리아",
Url = "http://www.dotnetkorea.com",
Description = "박용준 MVP 개인 홈페이지" },
new Site { Id = 6, Title = "VisualAcademy",
Url = "https://www.youtube.com/user/visualacademy",
Description = "박용준 MVP 개인 유튜브 채널" },
new Site { Id = 7, Title = "ASP.NET",
Url = "http://www.asp.net",
Description = "ASP.NET 공식 사이트" }
};
return View(siteLists);
}
}
}
(3) Views 폴더의 Shared 폴더의 Components 폴더에 SiteList 폴더를 생성합니다. 이 폴더에 Default.cshtml 뷰 페이지를 생성하고 다음과 같이 코드를 작성합니다. 컬렉션 형태의 데이터를 받아서 반복 구문을 통해 UI를 만들어 낸다.
/Views/Shared/Components/SiteList/Default.cshtml
@model List<DotNetNote.Models.Site>
<ul>
@foreach (var t in Model)
{
<li><a href="@t.Url" target="_blank">@t.Title (@t.Description)</a></li>
}
</ul>
(4) SiteList 폴더의 Default.cshtml 뷰 페이지와 같은 뷰 페이지를 같은 폴더에 Index.cshtml 파일로 생성합니다. 뷰 컴포넌트 호출 시 기본값이 아닌 다른 이름으로 호출하는 걸 테스트해보기 위함입니다.
/Views/Shared/SiteList/Index.cshtml
@model List<DotNetNote.Models.Site>
<ul>
@foreach (var t in Model)
{
<li><a href="@t.Url" target="_blank">@t.Title (@t.Description)</a></li>
}
</ul>
(5) SiteList 뷰 컴포넌트를 테스트하기 위해 ViewComponentDemo 컨트롤러에 다음과 같이 SiteListDemo 액션 메서드를 추가합니다.
/Controllers/ViewComponentDemoController.cs에 액션 메서드 추가
/// <summary>
/// SiteListViewComponent 사용 데모
/// </summary>
public IActionResult SiteListDemo()
{
return View();
}
(6) 마지막으로 SiteListDemo.cshtml 뷰 페이지를 작성합니다. 뷰 컴포넌트를 호출하는 코드를 사용하여 TechList와 Copyright 뷰 컴포넌트를 호출합니다.
/Views/ViewComponentDemo/SiteListDemo.cshtml
@{
Layout = null;
}
<h3>현재 사이트와 관련된 추천 사이트</h3>
@await Component.InvokeAsync("SiteList", "Index")
(7) 현재 프로젝트를 시작 프로젝트로 설정 후 Ctrl+F5로 실행합니다. 웹 브라우저에 /ViewComponentDemo/SiteListDemo 경로를 요청하면 다음과 같이 출력됩니다. List<T>
형태로 저장된 문자열 데이터가 UI 코드와 섞여서 출력됩니다.
그림: SiteList 뷰 컴포넌트 실행
32.7.5. 마무리
뷰 컴포넌트는 메인 페이지와 같이 한 페이지에 여러 개의 내용이 출력되는 경우, 하나 하나를 모듈 단위로 쪼개서 관리하고자 할 때 사용합니다. 뷰 컴포넌트로 조각 기능을 만들어서 원하는 곳에서 호출해서 사용할 수 있습니다.