32. 뷰 컴포넌트

  • 17 minutes to read

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 &copy; @DateTime.Now.Year all right reserved.
</div>

뷰 컴포넌트의 뷰 페이지의 기본 이름은 Default.cshtml입니다.

(4) 같은 경로에 Details.cshtml 뷰 페이지를 추가한 후 다음과 같이 코드를 작성합니다. 뷰 컴포넌트에서 서로 다른 뷰를 호출하는 걸 테스트하기 위해서 코드만 조금 바꾸었습니다.

/Views/Shared/Components/Copyright/Details.cshtml
<div class="text-center">
    Copyright &copy; @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 &copy; @DateTime.Now.Year all rights reserved.
</div>

C:\DotNetNote6\DotNetNote\DotNetNote\DotNetNote\Views\Shared\Components\Copyright\Details.cshtml

<div class="text-center">
    Copyright &copy; @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. 마무리

뷰 컴포넌트는 메인 페이지와 같이 한 페이지에 여러 개의 내용이 출력되는 경우, 하나 하나를 모듈 단위로 쪼개서 관리하고자 할 때 사용합니다. 뷰 컴포넌트로 조각 기능을 만들어서 원하는 곳에서 호출해서 사용할 수 있습니다.

VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com