ASP.NET Core의 보기 구성 요소
작성자: Rick Anderson
뷰 구성 요소
뷰 구성 요소는 부분 보기와 유사하지만 훨씬 강력합니다. 보기 구성 요소는 모델 바인딩을 사용하지 않으며 보기 구성 요소를 호출할 때 전달된 데이터에 따라 달라집니다. 이 문서는 컨트롤러 및 보기를 사용하여 작성되었지만, 보기 구성 요소는 RazorPages와 함께 사용할 수도 있습니다.
보기 구성 요소는 다음과 같은 특징을 갖고 있습니다.
- 전체 응답보다는 청크를 렌더링합니다.
- 컨트롤러 및 보기 간에서 발견할 수 있는 것과 동일한 문제의 분리 및 테스트 가능성의 이점을 포함합니다.
- 매개 변수 및 비즈니스 논리를 포함할 수 있습니다.
- 일반적으로 레이아웃 페이지에서 호출됩니다.
보기 구성 요소는 다음과 같이 부분 보기로는 너무 복잡한 재사용 가능 렌더링 논리를 갖는 모든 곳에서 사용할 수 있습니다.
- 동적 탐색 메뉴
- 데이터베이스를 쿼리하는 태그 클라우드
- 로그인 패널
- 쇼핑 카트
- 최근에 게시된 문서
- 블로그의 사이드바 콘텐츠
- 모든 페이지에 렌더링되고 사용자의 로그인 상태에 따라 로그아웃 또는 로그인 링크를 표시하는 로그인 패널
보기 구성 요소는 다음 두 부분으로 구성됩니다.
- 일반적으로 ViewComponent에서 파생된 클래스
- 반환되는 결과(일반적으로 보기)입니다.
컨트롤러와 마찬가지로 보기 구성 요소는 POCO일 수 있지만 대부분의 개발자는 ViewComponent에서 파생하여 사용 가능한 메서드와 속성을 활용합니다.
보기 구성 요소가 앱의 사양을 충족하는지 고려할 때 Razor 구성 요소를 대신 사용하는 방안도 고려해보세요. Razor 구성 요소 역시 태그와 C# 코드를 결합하여 다시 사용할 수 있는 UI 단위를 생성합니다. Razor 구성 요소는 클라이언트 쪽 UI 논리 및 컴퍼지션을 제공할 때 개발자 생산성을 위해 설계되었습니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요. 구성 요소를 MVC 또는 Pages 앱에 통합 Razor 하는 방법에 대한 자세한 내용은 MVC 또는 Razor Razor Pages와 ASP.NET Core Razor 구성 요소 통합을 참조하세요.
보기 구성 요소 만들기
이 섹션에서는 보기 구성 요소를 만들기 위한 높은 수준의 요구 사항이 포함되어 있습니다. 이 문서의 뒷부분에서는 각 단계를 자세히 검토하고 보기 구성 요소를 만들어봅니다.
보기 구성 요소 클래스
다음 중 한 가지 방법을 사용하여 보기 구성 요소 클래스를 만들 수 있습니다.
- ViewComponent에서 파생
[ViewComponent]
특성을 사용하여 클래스를 데코레이팅하거나[ViewComponent]
특성이 사용된 클래스에서 파생- 이름이 접미사로 끝나는 클래스 만들기
ViewComponent
컨트롤러와 마찬가지로 보기 구성 요소는 공용, 비중첩 및 비추상 클래스이어야 합니다. 보기 구성 요소의 이름은 ViewComponent
접미사가 제거된 클래스 이름입니다. 또한 Name 속성을 사용하여 명시적으로 지정할 수도 있습니다.
보기 구성 요소 클래스는 다음과 같은 특징을 갖고 있습니다.
대/소문자를 구분하지 않는 ViewComponent
접미사가 있는 클래스가 보기 구성 요소로 처리되지 않도록 하려면 [NonViewComponent]
특성을 사용하여 클래스를 데코레이트하세요.
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
뷰 구성 요소 메서드
보기 구성 요소는 다음에서 논리를 정의합니다.
Task<IViewComponentResult>
를 반환하는InvokeAsync
메서드입니다.- IViewComponentResult를 반환하는
Invoke
동기 메서드입니다.
매개 변수는 모델 바인딩이 아니라 보기 구성 요소 호출에서 직접 가져옵니다. 보기 구성 요소는 요청을 직접 처리하지 않습니다. 일반적으로 보기 구성 요소는 모델을 초기화하고 View
메서드를 호출하여 보기에 전달합니다. 요약해보면 보기 구성 요소 메서드는 다음과 같습니다.
Task<IViewComponentResult>
를 반환하는InvokeAsync
메서드 또는IViewComponentResult
를 반환하는 동기Invoke
메서드를 정의합니다.- 일반적으로 ViewComponent.View 메서드를 호출하여 모델을 초기화하고 그것을 보기에 전달합니다.
- 매개 변수는 HTTP가 아닌 호출 메서드에서 가져옵니다. 모델 바인딩이 없습니다.
- HTTP 엔드포인트로 직접 연결할 수 없습니다. 일반적으로 보기에서 호출됩니다. 보기 구성 요소는 요청을 처리하지 않습니다.
- 현재 HTTP 요청의 세부 정보가 아닌 시그니처에 오버로드됩니다.
보기 검색 경로
런타임은 다음 경로에서 뷰를 검색합니다.
- /Views/{Controller Name}/Components/{View Component Name}/{View Name}
- /Views/Shared/Components/{View Component Name}/{View Name}
- /Pages/Shared/Components/{View Component Name}/{View Name}
- /Areas/{Area Name}/views/Shared/Components/{View Component Name}/{View Name}
검색 경로는 컨트롤러 + 보기 및 Razor Pages를 사용하는 프로젝트에 적용됩니다.
보기 구성 요소에 대한 기본 보기 이름은 Default
이며, 이는 일반적으로 보기 파일의 이름이 Default.cshtml
로 지정됨을 의미합니다. 보기 구성 요소 결과를 만들거나 View
메서드를 호출할 때 다른 보기 이름을 지정할 수 있습니다.
보기 파일 이름을 Default.cshtml
로 지정하고 Views/Shared/Components/{View Component Name}/{View Name} 경로를 사용하는 것이 좋습니다. PriorityList
이 샘플에서 사용되는 뷰 구성 요소는 뷰 구성 요소 뷰에 사용됩니다Views/Shared/Components/PriorityList/Default.cshtml
.
보기 검색 경로 사용자 지정
보기 검색 경로를 사용자 지정하려면 Razor의 ViewLocationFormats 컬렉션을 수정합니다. 예를 들어 경로 /Components/{View Component Name}/{View Name}
내에서 보기를 검색하려면 컬렉션에 새 항목을 추가하면 됩니다.
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
이전 코드에서 자리 표시자 {0}
은 Components/{View Component Name}/{View Name}
경로를 나타냅니다.
보기 구성 요소 호출
보기 구성 요소를 사용하려면 보기에서 다음을 호출합니다.
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
매개 변수는 InvokeAsync
메서드에 전달됩니다. PriorityList
아티클에서 개발된 뷰 구성 요소는 뷰 파일에서 Views/ToDo/Index.cshtml
호출됩니다. 다음 코드에서 InvokeAsync
메서드는 매개 변수 두 개를 사용하여 호출합니다.
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
보기 구성 요소를 태그 도우미로 호출
보기 구성 요소를 태그 도우미로 호출할 수 있습니다.
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
태그 도우미에 대한 파스칼식 클래스 및 메서드 매개 변수는 케밥식으로 번역됩니다. 뷰 구성 요소를 호출하는 태그 도우미는 <vc></vc>
요소를 사용합니다. 보기 구성 요소는 다음과 같이 지정됩니다.
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
보기 구성 요소를 태그 도우미로 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다. 보기 구성 요소가 MyWebApp
이라는 어셈블리에 있는 경우 다음 지시문을 _ViewImports.cshtml
파일에 추가합니다.
@addTagHelper *, MyWebApp
보기 구성 요소를 참조하는 모든 파일에 보기 구성 요소를 태그 도우미로 등록할 수 있습니다. 태그 도우미를 등록하는 방법에 대한 자세한 내용은 태그 도우미 범위 관리를 참조하세요.
이 자습서에 사용된 InvokeAsync
메서드:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
이전 표시에서 PriorityList
보기 구성 요소는 priority-list
가 됩니다. 보기 구성 요소에 대한 매개 변수는 케밥식의 특성으로 전달됩니다.
컨트롤러에서 보기 구성 요소 직접 호출
일반적으로 보기 구성 요소는 보기에서 호출되지만 컨트롤러 메서드에서 직접 호출할 수도 있습니다. 보기 구성 요소는 컨트롤러 같은 엔드포인트를 정의하지 않지만 ViewComponentResult
의 콘텐츠를 반환하는 컨트롤러 동작을 구현할 수 있습니다.
다음은 보기 구성 요소가 컨트롤러에서 직접 호출되는 예제입니다.
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
기본 보기 구성 요소 만들기
시작 코드를 다운로드, 빌드 및 테스트합니다. ToDo 항목의 목록을 표시하는 ToDo
컨트롤러가 포함된 간단한 프로젝트입니다.
우선 순위 및 완료 상태를 전달하기 위한 컨트롤러 업데이트
우선 순위 및 완료 상태 매개 변수를 사용하도록 Index
메서드를 업데이트합니다.
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
ViewComponent 클래스 추가
ViewComponents/PriorityListViewComponent.cs
에 ViewComponent 클래스를 추가합니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.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);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
코드에 대한 참고 사항:
보기 구성 요소 클래스는 프로젝트의 모든 폴더에 포함될 수 있습니다.
클래스 이름인 PriorityListViewComponent가 ViewComponent 접미사로 끝나기 때문에 보기에서 클래스 구성 요소를 참조할 때 런타임은 문자열
PriorityList
를 사용합니다.[ViewComponent]
특성은 보기 구성 요소를 참조하는 데 사용되는 이름을 변경할 수 있습니다. 예를 들어 클래스의 이름을 다음XYZ
특성으로 지정[ViewComponent]
할 수 있습니다.[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
이전 코드의
[ViewComponent]
특성은 보기 구성 요소 선택기가 다음을 사용하도록 지시합니다.- 구성 요소와 연결된 보기를 검색할 때의 이름
PriorityList
- 보기에서 클래스 구성 요소를 참조할 때의 문자열 “PriorityList”
- 구성 요소와 연결된 보기를 검색할 때의 이름
이 구성 요소에서는 종속성 주입을 사용하여 데이터 컨텍스트를 사용할 수 있도록 합니다.
InvokeAsync
는 보기에서 호출할 수 있는 메서드를 노출하며 임의의 개수의 인수를 사용할 수 있습니다.InvokeAsync
메서드는isDone
및maxPriority
매개 변수를 만족하는ToDo
항목 집합을 반환합니다.
보기 구성 요소 Razor 보기 만들기
Views/Shared/Components 폴더를 만듭니다. 이 폴더의 이름은 Components로 지정되어야만 합니다.
Views/Shared/Components/PriorityList 폴더를 만듭니다. 이 폴더 이름은 보기 구성 요소 클래스의 이름 또는 클래스 이름에서 접미사를 뺀 이름과 일치해야 합니다.
ViewComponent
특성을 사용한 경우 클래스 이름은 특성 지정과 일치해야 합니다.Views/Shared/Components/PriorityList/Default.cshtml
Razor 보기를 만듭니다.@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Razor 보기는
TodoItem
목록을 가져와 표시합니다. 뷰 구성 요소InvokeAsync
메서드가 뷰 의 이름을 전달하지 않는 경우 기본값 은 규칙에 따라 뷰 이름에 사용됩니다. 특정 컨트롤러에 대한 기본 스타일 지정을 재정의하려면 컨트롤러 관련 뷰 폴더에 뷰를 추가합니다(예: Views/ToDo/Components/PriorityList/Default.cshtml).뷰 구성 요소가 컨트롤러별인 경우 컨트롤러별 폴더에 추가할 수 있습니다. 예를 들어
Views/ToDo/Components/PriorityList/Default.cshtml
는 컨트롤러에 따라 다릅니다.div
우선 순위 목록 구성 요소에 대한 호출을 포함하는 호출을 파일 맨 아래에 추가합니다Views/ToDo/index.cshtml
.</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
@await Component.InvokeAsync
태그는 호출하는 보기 구성 요소에 대한 구문을 보여 줍니다. 첫 번째 인수는 실행하거나 호출하려는 구성 요소의 이름입니다. 후속 매개 변수는 구성 요소에 전달됩니다. InvokeAsync
는 임의 개수의 인수를 사용할 수 있습니다.
앱을 테스트합니다. 다음 이미지는 ToDo 목록 및 우선 순위 항목을 보여 줍니다.
보기 구성 요소는 컨트롤러에서 직접 호출할 수 있습니다.
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
보기 구성 요소 이름 지정
복잡한 보기 구성 요소에서는 조건에 따라 기본값이 아닌 보기를 지정해야 할 수도 있습니다. 다음 코드는 InvokeAsync
메서드에서 "PVC" 보기를 지정하는 방법을 보여 줍니다. PriorityListViewComponent
클래스에서 InvokeAsync
메서드를 수정합니다.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
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);
}
Views/Shared/Components/PriorityList/Default.cshtml
파일을 Views/Shared/Components/PriorityList/PVC.cshtml
보기에 복사합니다. PVC 보기가 사용되었음을 나타내는 제목을 추가합니다.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
앱을 실행하고 PVC 보기를 확인합니다.
PVC 보기가 렌더링되지 않는다면 우선 순위가 4 이상인 보기 구성 요소를 호출하고 있는지 확인해봅니다.
보기 경로 검토
우선 순위 보기가 반환되지 않도록 우선 순위 매개 변수를 3 이하로 변경합니다.
Views/ToDo/Components/PriorityList/Default.cshtml
의 이름을 일시적으로1Default.cshtml
로 바꿉니다.앱을 테스트하면 다음 오류가 발생합니다.
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Views/ToDo/Components/PriorityList/1Default.cshtml
을Views/Shared/Components/PriorityList/Default.cshtml
에 복사합니다.Shared ToDo 보기 구성 요소 보기에 일부 태그를 추가하여 보기가 Shared 폴더에 있음을 표시합니다.
Shared 구성 요소 뷰를 테스트합니다.
하드 코딩된 문자열 방지
컴파일 시간 보안을 위해 하드 코딩된 보기 구성 요소 이름을 클래스 이름으로 바꿉니다. "ViewComponent" 접미사를 사용하지 않도록 PriorityListViewComponent.cs 파일을 업데이트합니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
보기 파일:
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
CLR 형식을 사용하는 Component.InvokeAsync
메서드의 오버로드는 typeof
연산자를 사용합니다.
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
동기 작업 수행
비동기 작업이 필요하지 않은 경우 프레임워크는 동기 Invoke
메서드 호출을 처리합니다. 다음 메서드는 동기 Invoke
보기 구성 요소를 만듭니다.
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
보기 구성 요소의 Razor 파일:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
보기 구성 요소는 다음 방법 중 하나를 사용하여 Razor 파일(예: Views/Home/Index.cshtml
)에서 호출됩니다.
IViewComponentHelper 접근 방법을 사용하려면 Component.InvokeAsync
를 호출합니다.
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
태그 도우미를 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다(보기 구성 요소는 MyWebApp
이라는 어셈블리에 있음).
@addTagHelper *, MyWebApp
Razor 태그 파일에서 보기 구성 요소 태그 도우미를 사용합니다.
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
PriorityList.Invoke
의 메서드 시그니처는 동기식이지만, Razor는 태그 파일에서 Component.InvokeAsync
를 사용하여 메서드를 찾고 호출합니다.
추가 리소스
뷰 구성 요소
뷰 구성 요소는 부분 보기와 유사하지만 훨씬 강력합니다. 보기 구성 요소는 모델 바인딩을 사용하지 않으며 보기 구성 요소를 호출할 때 전달된 데이터에 따라 달라집니다. 이 문서는 컨트롤러 및 보기를 사용하여 작성되었지만, 보기 구성 요소는 RazorPages와 함께 사용할 수도 있습니다.
보기 구성 요소는 다음과 같은 특징을 갖고 있습니다.
- 전체 응답보다는 청크를 렌더링합니다.
- 컨트롤러 및 보기 간에서 발견할 수 있는 것과 동일한 문제의 분리 및 테스트 가능성의 이점을 포함합니다.
- 매개 변수 및 비즈니스 논리를 포함할 수 있습니다.
- 일반적으로 레이아웃 페이지에서 호출됩니다.
보기 구성 요소는 다음과 같이 부분 보기로는 너무 복잡한 재사용 가능 렌더링 논리를 갖는 모든 곳에서 사용할 수 있습니다.
- 동적 탐색 메뉴
- 데이터베이스를 쿼리하는 태그 클라우드
- 로그인 패널
- 쇼핑 카트
- 최근에 게시된 문서
- 블로그의 사이드바 콘텐츠
- 모든 페이지에 렌더링되고 사용자의 로그인 상태에 따라 로그아웃 또는 로그인 링크를 표시하는 로그인 패널
보기 구성 요소는 다음 두 부분으로 구성됩니다.
- 일반적으로 ViewComponent에서 파생된 클래스
- 반환되는 결과(일반적으로 보기)입니다.
컨트롤러와 마찬가지로 보기 구성 요소는 POCO일 수 있지만 대부분의 개발자는 ViewComponent에서 파생하여 사용 가능한 메서드와 속성을 활용합니다.
보기 구성 요소가 앱의 사양을 충족하는지 고려할 때 Razor 구성 요소를 대신 사용하는 방안도 고려해보세요. Razor 구성 요소 역시 태그와 C# 코드를 결합하여 다시 사용할 수 있는 UI 단위를 생성합니다. Razor 구성 요소는 클라이언트 쪽 UI 논리 및 컴퍼지션을 제공할 때 개발자 생산성을 위해 설계되었습니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요. 구성 요소를 MVC 또는 Pages 앱에 통합 Razor 하는 방법에 대한 자세한 내용은 MVC 또는 Razor Razor Pages와 ASP.NET Core Razor 구성 요소 통합을 참조하세요.
보기 구성 요소 만들기
이 섹션에서는 보기 구성 요소를 만들기 위한 높은 수준의 요구 사항이 포함되어 있습니다. 이 문서의 뒷부분에서는 각 단계를 자세히 검토하고 보기 구성 요소를 만들어봅니다.
보기 구성 요소 클래스
다음 중 한 가지 방법을 사용하여 보기 구성 요소 클래스를 만들 수 있습니다.
- ViewComponent에서 파생
[ViewComponent]
특성을 사용하여 클래스를 데코레이팅하거나[ViewComponent]
특성이 사용된 클래스에서 파생- 이름이 접미사로 끝나는 클래스 만들기
ViewComponent
컨트롤러와 마찬가지로 보기 구성 요소는 공용, 비중첩 및 비추상 클래스이어야 합니다. 보기 구성 요소의 이름은 ViewComponent
접미사가 제거된 클래스 이름입니다. 또한 Name 속성을 사용하여 명시적으로 지정할 수도 있습니다.
보기 구성 요소 클래스는 다음과 같은 특징을 갖고 있습니다.
대/소문자를 구분하지 않는 ViewComponent
접미사가 있는 클래스가 보기 구성 요소로 처리되지 않도록 하려면 [NonViewComponent]
특성을 사용하여 클래스를 데코레이트하세요.
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
뷰 구성 요소 메서드
보기 구성 요소는 다음에서 논리를 정의합니다.
Task<IViewComponentResult>
를 반환하는InvokeAsync
메서드입니다.- IViewComponentResult를 반환하는
Invoke
동기 메서드입니다.
매개 변수는 모델 바인딩이 아니라 보기 구성 요소 호출에서 직접 가져옵니다. 보기 구성 요소는 요청을 직접 처리하지 않습니다. 일반적으로 보기 구성 요소는 모델을 초기화하고 View
메서드를 호출하여 보기에 전달합니다. 요약해보면 보기 구성 요소 메서드는 다음과 같습니다.
Task<IViewComponentResult>
를 반환하는InvokeAsync
메서드 또는IViewComponentResult
를 반환하는 동기Invoke
메서드를 정의합니다.- 일반적으로 ViewComponent.View 메서드를 호출하여 모델을 초기화하고 그것을 보기에 전달합니다.
- 매개 변수는 HTTP가 아닌 호출 메서드에서 가져옵니다. 모델 바인딩이 없습니다.
- HTTP 엔드포인트로 직접 연결할 수 없습니다. 일반적으로 보기에서 호출됩니다. 보기 구성 요소는 요청을 처리하지 않습니다.
- 현재 HTTP 요청의 세부 정보가 아닌 시그니처에 오버로드됩니다.
보기 검색 경로
런타임은 다음 경로에서 뷰를 검색합니다.
- /Views/{Controller Name}/Components/{View Component Name}/{View Name}
- /Views/Shared/Components/{View Component Name}/{View Name}
- /Pages/Shared/Components/{View Component Name}/{View Name}
- /Areas/{Area Name}/views/Shared/Components/{View Component Name}/{View Name}
검색 경로는 컨트롤러 + 보기 및 Razor Pages를 사용하는 프로젝트에 적용됩니다.
보기 구성 요소에 대한 기본 보기 이름은 Default
이며, 이는 일반적으로 보기 파일의 이름이 Default.cshtml
로 지정됨을 의미합니다. 보기 구성 요소 결과를 만들거나 View
메서드를 호출할 때 다른 보기 이름을 지정할 수 있습니다.
보기 파일 이름을 Default.cshtml
로 지정하고 Views/Shared/Components/{View Component Name}/{View Name} 경로를 사용하는 것이 좋습니다. PriorityList
이 샘플에서 사용되는 뷰 구성 요소는 뷰 구성 요소 뷰에 사용됩니다Views/Shared/Components/PriorityList/Default.cshtml
.
보기 검색 경로 사용자 지정
보기 검색 경로를 사용자 지정하려면 Razor의 ViewLocationFormats 컬렉션을 수정합니다. 예를 들어 경로 /Components/{View Component Name}/{View Name}
내에서 보기를 검색하려면 컬렉션에 새 항목을 추가하면 됩니다.
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
이전 코드에서 자리 표시자 {0}
은 Components/{View Component Name}/{View Name}
경로를 나타냅니다.
보기 구성 요소 호출
보기 구성 요소를 사용하려면 보기에서 다음을 호출합니다.
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
매개 변수는 InvokeAsync
메서드에 전달됩니다. PriorityList
아티클에서 개발된 뷰 구성 요소는 뷰 파일에서 Views/ToDo/Index.cshtml
호출됩니다. 다음 코드에서 InvokeAsync
메서드는 매개 변수 두 개를 사용하여 호출합니다.
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
보기 구성 요소를 태그 도우미로 호출
보기 구성 요소를 태그 도우미로 호출할 수 있습니다.
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
태그 도우미에 대한 파스칼식 클래스 및 메서드 매개 변수는 케밥식으로 번역됩니다. 뷰 구성 요소를 호출하는 태그 도우미는 <vc></vc>
요소를 사용합니다. 보기 구성 요소는 다음과 같이 지정됩니다.
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
보기 구성 요소를 태그 도우미로 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다. 보기 구성 요소가 MyWebApp
이라는 어셈블리에 있는 경우 다음 지시문을 _ViewImports.cshtml
파일에 추가합니다.
@addTagHelper *, MyWebApp
보기 구성 요소를 참조하는 모든 파일에 보기 구성 요소를 태그 도우미로 등록할 수 있습니다. 태그 도우미를 등록하는 방법에 대한 자세한 내용은 태그 도우미 범위 관리를 참조하세요.
이 자습서에 사용된 InvokeAsync
메서드:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
이전 표시에서 PriorityList
보기 구성 요소는 priority-list
가 됩니다. 보기 구성 요소에 대한 매개 변수는 케밥식의 특성으로 전달됩니다.
컨트롤러에서 보기 구성 요소 직접 호출
일반적으로 보기 구성 요소는 보기에서 호출되지만 컨트롤러 메서드에서 직접 호출할 수도 있습니다. 보기 구성 요소는 컨트롤러 같은 엔드포인트를 정의하지 않지만 ViewComponentResult
의 콘텐츠를 반환하는 컨트롤러 동작을 구현할 수 있습니다.
다음은 보기 구성 요소가 컨트롤러에서 직접 호출되는 예제입니다.
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
기본 보기 구성 요소 만들기
시작 코드를 다운로드, 빌드 및 테스트합니다. ToDo 항목의 목록을 표시하는 ToDo
컨트롤러가 포함된 간단한 프로젝트입니다.
우선 순위 및 완료 상태를 전달하기 위한 컨트롤러 업데이트
우선 순위 및 완료 상태 매개 변수를 사용하도록 Index
메서드를 업데이트합니다.
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
ViewComponent 클래스 추가
ViewComponents/PriorityListViewComponent.cs
에 ViewComponent 클래스를 추가합니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.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);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
코드에 대한 참고 사항:
보기 구성 요소 클래스는 프로젝트의 모든 폴더에 포함될 수 있습니다.
클래스 이름인 PriorityListViewComponent가 ViewComponent 접미사로 끝나기 때문에 보기에서 클래스 구성 요소를 참조할 때 런타임은 문자열
PriorityList
를 사용합니다.[ViewComponent]
특성은 보기 구성 요소를 참조하는 데 사용되는 이름을 변경할 수 있습니다. 예를 들어 클래스의 이름을 다음XYZ
특성으로 지정[ViewComponent]
할 수 있습니다.[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
이전 코드의
[ViewComponent]
특성은 보기 구성 요소 선택기가 다음을 사용하도록 지시합니다.- 구성 요소와 연결된 보기를 검색할 때의 이름
PriorityList
- 보기에서 클래스 구성 요소를 참조할 때의 문자열 “PriorityList”
- 구성 요소와 연결된 보기를 검색할 때의 이름
이 구성 요소에서는 종속성 주입을 사용하여 데이터 컨텍스트를 사용할 수 있도록 합니다.
InvokeAsync
는 보기에서 호출할 수 있는 메서드를 노출하며 임의의 개수의 인수를 사용할 수 있습니다.InvokeAsync
메서드는isDone
및maxPriority
매개 변수를 만족하는ToDo
항목 집합을 반환합니다.
보기 구성 요소 Razor 보기 만들기
Views/Shared/Components 폴더를 만듭니다. 이 폴더의 이름은 Components로 지정되어야만 합니다.
Views/Shared/Components/PriorityList 폴더를 만듭니다. 이 폴더 이름은 보기 구성 요소 클래스의 이름 또는 클래스 이름에서 접미사를 뺀 이름과 일치해야 합니다.
ViewComponent
특성을 사용한 경우 클래스 이름은 특성 지정과 일치해야 합니다.Views/Shared/Components/PriorityList/Default.cshtml
Razor 보기를 만듭니다.@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Razor 보기는
TodoItem
목록을 가져와 표시합니다. 뷰 구성 요소InvokeAsync
메서드가 뷰 의 이름을 전달하지 않는 경우 기본값 은 규칙에 따라 뷰 이름에 사용됩니다. 특정 컨트롤러에 대한 기본 스타일 지정을 재정의하려면 컨트롤러 관련 뷰 폴더에 뷰를 추가합니다(예: Views/ToDo/Components/PriorityList/Default.cshtml).뷰 구성 요소가 컨트롤러별인 경우 컨트롤러별 폴더에 추가할 수 있습니다. 예를 들어
Views/ToDo/Components/PriorityList/Default.cshtml
는 컨트롤러에 따라 다릅니다.div
우선 순위 목록 구성 요소에 대한 호출을 포함하는 호출을 파일 맨 아래에 추가합니다Views/ToDo/index.cshtml
.</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
@await Component.InvokeAsync
태그는 호출하는 보기 구성 요소에 대한 구문을 보여 줍니다. 첫 번째 인수는 실행하거나 호출하려는 구성 요소의 이름입니다. 후속 매개 변수는 구성 요소에 전달됩니다. InvokeAsync
는 임의 개수의 인수를 사용할 수 있습니다.
앱을 테스트합니다. 다음 이미지는 ToDo 목록 및 우선 순위 항목을 보여 줍니다.
보기 구성 요소는 컨트롤러에서 직접 호출할 수 있습니다.
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
보기 구성 요소 이름 지정
복잡한 보기 구성 요소에서는 조건에 따라 기본값이 아닌 보기를 지정해야 할 수도 있습니다. 다음 코드는 InvokeAsync
메서드에서 "PVC" 보기를 지정하는 방법을 보여 줍니다. PriorityListViewComponent
클래스에서 InvokeAsync
메서드를 수정합니다.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
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);
}
Views/Shared/Components/PriorityList/Default.cshtml
파일을 Views/Shared/Components/PriorityList/PVC.cshtml
보기에 복사합니다. PVC 보기가 사용되었음을 나타내는 제목을 추가합니다.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
앱을 실행하고 PVC 보기를 확인합니다.
PVC 보기가 렌더링되지 않는다면 우선 순위가 4 이상인 보기 구성 요소를 호출하고 있는지 확인해봅니다.
보기 경로 검토
우선 순위 보기가 반환되지 않도록 우선 순위 매개 변수를 3 이하로 변경합니다.
Views/ToDo/Components/PriorityList/Default.cshtml
의 이름을 일시적으로1Default.cshtml
로 바꿉니다.앱을 테스트하면 다음 오류가 발생합니다.
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Views/ToDo/Components/PriorityList/1Default.cshtml
을Views/Shared/Components/PriorityList/Default.cshtml
에 복사합니다.Shared ToDo 보기 구성 요소 보기에 일부 태그를 추가하여 보기가 Shared 폴더에 있음을 표시합니다.
Shared 구성 요소 뷰를 테스트합니다.
하드 코딩된 문자열 방지
컴파일 시간 보안을 위해 하드 코딩된 보기 구성 요소 이름을 클래스 이름으로 바꿉니다. "ViewComponent" 접미사를 사용하지 않도록 PriorityListViewComponent.cs 파일을 업데이트합니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
보기 파일:
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
CLR 형식을 사용하는 Component.InvokeAsync
메서드의 오버로드는 typeof
연산자를 사용합니다.
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
동기 작업 수행
비동기 작업이 필요하지 않은 경우 프레임워크는 동기 Invoke
메서드 호출을 처리합니다. 다음 메서드는 동기 Invoke
보기 구성 요소를 만듭니다.
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
보기 구성 요소의 Razor 파일:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
보기 구성 요소는 다음 방법 중 하나를 사용하여 Razor 파일(예: Views/Home/Index.cshtml
)에서 호출됩니다.
IViewComponentHelper 접근 방법을 사용하려면 Component.InvokeAsync
를 호출합니다.
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
태그 도우미를 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다(보기 구성 요소는 MyWebApp
이라는 어셈블리에 있음).
@addTagHelper *, MyWebApp
Razor 태그 파일에서 보기 구성 요소 태그 도우미를 사용합니다.
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
PriorityList.Invoke
의 메서드 시그니처는 동기식이지만, Razor는 태그 파일에서 Component.InvokeAsync
를 사용하여 메서드를 찾고 호출합니다.
추가 리소스
뷰 구성 요소
뷰 구성 요소는 부분 보기와 유사하지만 훨씬 강력합니다. 뷰 구성 요소는 모델 바인딩을 사용하지 않으며 호출할 때 제공되는 데이터에만 의존합니다. 이 문서는 컨트롤러 및 보기를 사용하여 작성되었지만, 보기 구성 요소는 Razor Pages와 함께 사용할 수도 있습니다.
보기 구성 요소는 다음과 같은 특징을 갖고 있습니다.
- 전체 응답보다는 청크를 렌더링합니다.
- 컨트롤러 및 보기 간에서 발견할 수 있는 것과 동일한 문제의 분리 및 테스트 가능성의 이점을 포함합니다.
- 매개 변수 및 비즈니스 논리를 포함할 수 있습니다.
- 일반적으로 레이아웃 페이지에서 호출됩니다.
보기 구성 요소는 다음과 같이 부분 보기로는 너무 복잡한 재사용 가능한 렌더링 논리를 갖는 모든 곳에서 사용할 수 있습니다.
- 동적 탐색 메뉴
- 태그 클라우드(여기서는 데이터베이스를 쿼리합니다.)
- 로그인 패널
- 쇼핑 카트
- 최근에 게시된 문서
- 일반적인 블로그의 사이드바 콘텐츠
- 모든 페이지에 렌더링되고 사용자의 로그인 상태에 따라 로그아웃 또는 로그인 링크를 표시하는 로그인 패널
뷰 구성 요소는 클래스(일반적으로 파생) ViewComponent와 반환되는 결과(일반적으로 뷰)의 두 부분으로 구성됩니다. 컨트롤러와 마찬가지로 보기 구성 요소는 POCO일 수 있지만 개발자 대부분은 ViewComponent
에서 파생하여 사용 가능 메서드와 속성을 활용합니다.
보기 구성 요소가 앱의 사양을 충족하는지 고려할 때 Razor 구성 요소를 대신 사용하는 방안도 고려해보세요. Razor 구성 요소 역시 태그와 C# 코드를 결합하여 다시 사용할 수 있는 UI 단위를 생성합니다. Razor 구성 요소는 클라이언트 쪽 UI 논리 및 컴퍼지션을 제공할 때 개발자 생산성을 위해 설계되었습니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요. 구성 요소를 MVC 또는 Pages 앱에 통합 Razor 하는 방법에 대한 자세한 내용은 MVC 또는 Razor Razor Pages와 ASP.NET Core Razor 구성 요소 통합을 참조하세요.
뷰 구성 요소 만들기
이 섹션에서는 보기 구성 요소를 만들기 위한 높은 수준의 요구 사항이 포함되어 있습니다. 이 문서의 뒷부분에서는 각 단계를 자세히 검토하고 보기 구성 요소를 만들어봅니다.
보기 구성 요소 클래스
다음 중 한 가지 방법을 사용하여 보기 구성 요소 클래스를 만들 수 있습니다.
- ViewComponent에서 파생
[ViewComponent]
특성을 사용하여 클래스를 데코레이팅하거나[ViewComponent]
특성이 사용된 클래스에서 파생- 이름이 ViewComponent 접미사로 끝나는 클래스 만들기
컨트롤러와 마찬가지로 보기 구성 요소는 공용, 비중첩 및 비추상 클래스이어야 합니다. 보기 구성 요소의 이름은 "ViewComponent" 접미사가 제거된 클래스 이름입니다. 또한 ViewComponentAttribute.Name
속성을 사용하여 명시적으로 지정할 수도 있습니다.
보기 구성 요소 클래스는 다음과 같은 특징을 갖고 있습니다.
대/소문자를 구분하지 않는 ViewComponent 접미사가 있는 클래스가 보기 구성 요소로 처리되지 않도록 하려면 [NonViewComponent] 특성으로 클래스를 데코레이트합니다.
[NonViewComponent]
public class ReviewComponent
{
// ...
뷰 구성 요소 메서드
보기 구성 요소는 Task<IViewComponentResult>
를 반환하는 InvokeAsync
메서드 또는 IViewComponentResult
를 반환하는 동기 Invoke
메서드에서 해당 논리를 정의합니다. 매개 변수는 모델 바인딩이 아니라 보기 구성 요소 호출에서 직접 가져옵니다. 보기 구성 요소는 요청을 직접 처리하지 않습니다. 일반적으로 보기 구성 요소는 모델을 초기화하고 View
메서드를 호출하여 보기에 전달합니다. 요약해보면 보기 구성 요소 메서드는 다음과 같습니다.
Task<IViewComponentResult>
를 반환하는InvokeAsync
메서드 또는IViewComponentResult
를 반환하는 동기Invoke
메서드를 정의합니다.- 일반적으로 모델을 초기화하고
ViewComponent
View
메서드를 호출하여 이를 보기에 전달합니다. - 매개 변수는 HTTP가 아닌 호출 메서드에서 가져옵니다. 모델 바인딩이 없습니다.
- HTTP 엔드포인트로 직접 연결할 수 없습니다. (일반적으로 보기의) 코드에서 호출됩니다. 보기 구성 요소는 요청을 처리하지 않습니다.
- 현재 HTTP 요청의 세부 정보가 아닌 시그니처에 오버로드됩니다.
보기 검색 경로
런타임은 다음 경로에서 뷰를 검색합니다.
- /Views/{Controller Name}/Components/{View Component Name}/{View Name}
- /Views/Shared/Components/{View Component Name}/{View Name}
- /Pages/Shared/Components/{View Component Name}/{View Name}
- /Areas/{Area Name}/views/Shared/Components/{View Component Name}/{View Name}
검색 경로는 컨트롤러 + 보기 및 Razor Pages를 사용하는 프로젝트에 적용됩니다.
보기 구성 요소의 기본 보기 이름은 Default입니다. 즉, 보기 파일의 이름은 일반적으로 지정Default.cshtml
됩니다. 뷰 구성 요소 결과를 만들거나 View
메서드를 호출할 때 다른 뷰 이름을 지정할 수 있습니다.
보기 파일 Default.cshtml
의 이름을 지정하고 Views/Shared/Components/{View Component Name}/{View Name} 경로를 사용하는 것이 좋습니다. PriorityList
이 샘플에서 사용되는 뷰 구성 요소는 뷰 구성 요소 뷰에 사용됩니다Views/Shared/Components/PriorityList/Default.cshtml
.
보기 검색 경로 사용자 지정
보기 검색 경로를 사용자 지정하려면 Razor의 ViewLocationFormats 컬렉션을 수정합니다. 예를 들어 "/Components/{View Component Name}/{View Name}" 경로 내에서 보기를 검색하려면 컬렉션에 새 항목을 추가합니다.
services.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
이전 코드에서 "{0}" 자리 표시자는 "Components/{View Component Name}/{View Name}" 경로를 나타냅니다.
보기 구성 요소 호출
보기 구성 요소를 사용하려면 보기에서 다음을 호출합니다.
@await Component.InvokeAsync("Name of view component", {Anonymous Type Containing Parameters})
매개 변수는 InvokeAsync
메서드에 전달됩니다. PriorityList
아티클에서 개발된 뷰 구성 요소는 뷰 파일에서 Views/ToDo/Index.cshtml
호출됩니다. 다음에서 InvokeAsync
메서드는 두 매개 변수를 사용하여 호출됩니다.
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
태그 도우미로 보기 구성 요소 호출
ASP.NET Core 1.1 이상에서는 태그 도우미로 보기 구성 요소를 호출할 수 있습니다.
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
태그 도우미에 대한 파스칼식 클래스 및 메서드 매개 변수는 케밥식으로 번역됩니다. 뷰 구성 요소를 호출하는 태그 도우미는 <vc></vc>
요소를 사용합니다. 보기 구성 요소는 다음과 같이 지정됩니다.
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
보기 구성 요소를 태그 도우미로 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다. 뷰 구성 요소가 호출 MyWebApp
된 어셈블리에 있는 경우 파일에 다음 지시문을 _ViewImports.cshtml
추가합니다.
@addTagHelper *, MyWebApp
뷰 구성 요소를 참조하는 모든 파일에 뷰 구성 요소를 태그 도우미로 등록할 수 있습니다. 태그 도우미를 등록하는 방법에 대한 자세한 내용은 태그 도우미 범위 관리를 참조하세요.
이 자습서에 사용된 InvokeAsync
메서드:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
태그 도우미 태그:
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
위의 예제에서 PriorityList
보기 구성 요소는 priority-list
가 됩니다. 보기 구성 요소에 대한 매개 변수는 케밥식의 특성으로 전달됩니다.
컨트롤러에서 뷰 구성 요소 직접 호출
일반적으로 보기 구성 요소는 보기에서 호출되지만 컨트롤러 메서드에서 직접 호출할 수도 있습니다. 보기 구성 요소는 컨트롤러 같은 엔드포인트를 정의하지 않지만 ViewComponentResult
의 내용을 반환하는 컨트롤러 동작을 쉽게 구현할 수 있습니다.
이 예제에서는 보기 구성 요소가 컨트롤러에서 직접 호출됩니다.
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
연습: 간단한 뷰 구성 요소 만들기
시작 코드를 다운로드, 빌드 및 테스트합니다. ToDo 항목의 목록을 표시하는 ToDo
컨트롤러가 포함된 간단한 프로젝트입니다.
ViewComponent 클래스 추가
ViewComponents 폴더를 만들고 다음 PriorityListViewComponent
클래스를 추가합니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.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);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
코드에 대한 참고 사항:
보기 구성 요소 클래스는 프로젝트의 모든 폴더에 포함될 수 있습니다.
클래스 이름인 PriorityListViewComponent가 ViewComponent 접미사로 끝나기 때문에 보기에서 클래스 구성 요소를 참조할 때 런타임은 문자열
PriorityList
를 사용합니다.[ViewComponent]
특성은 보기 구성 요소를 참조하는 데 사용되는 이름을 변경할 수 있습니다. 예를 들어ViewComponent
특성으로 클래스의 이름을XYZ
로 지정할 수 있습니다.[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
이전 코드의
[ViewComponent]
특성은 보기 구성 요소 선택기가 다음을 사용하도록 지시합니다.- 구성 요소와 연결된 보기를 검색할 때의 이름
PriorityList
- 보기에서 클래스 구성 요소를 참조할 때의 문자열 “PriorityList”
- 구성 요소와 연결된 보기를 검색할 때의 이름
이 구성 요소에서는 종속성 주입을 사용하여 데이터 컨텍스트를 사용할 수 있도록 합니다.
InvokeAsync
는 보기에서 호출할 수 있는 메서드를 노출하며 임의의 개수의 인수를 사용할 수 있습니다.InvokeAsync
메서드는isDone
및maxPriority
매개 변수를 만족하는ToDo
항목 집합을 반환합니다.
보기 구성 요소 Razor 보기 만들기
Views/Shared/Components 폴더를 만듭니다. 이 폴더의 이름은
Components
로 지정해야만 합니다.Views/Shared/Components/PriorityList 폴더를 만듭니다. 이 폴더 이름은 보기 구성 요소 클래스의 이름 또는 클래스 이름에서 접미사를 뺀 이름과 일치해야 합니다(규칙을 준수하고 클래스 이름에 ViewComponent 접미사를 사용한 경우).
ViewComponent
특성을 사용한 경우 클래스 이름은 특성 지정과 일치해야 합니다.Views/Shared/Components/PriorityList/Default.cshtml
Razor 보기를 만듭니다.@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Razor 보기는
TodoItem
목록을 가져와 표시합니다. 뷰 구성 요소InvokeAsync
메서드가 뷰의 이름을 전달하지 않은 경우(샘플에서처럼) 규칙에 따라 뷰 이름으로 Default가 사용됩니다. 자습서의 뒷부분에서 뷰 이름을 전달하는 방법을 보여 줍니다. 특정 컨트롤러에 대한 기본 스타일 지정을 재정의하려면 컨트롤러 관련 뷰 폴더에 뷰를 추가합니다(예: Views/ToDo/Components/PriorityList/Default.cshtml).뷰 구성 요소가 컨트롤러별인 경우 컨트롤러별 폴더(
Views/ToDo/Components/PriorityList/Default.cshtml
)에 추가할 수 있습니다.div
우선 순위 목록 구성 요소에 대한 호출을 포함하는 호출을 파일 맨 아래에 추가합니다Views/ToDo/index.cshtml
.</table> <div> @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false }) </div>
@await Component.InvokeAsync
태그는 호출하는 보기 구성 요소에 대한 구문을 보여 줍니다. 첫 번째 인수는 실행하거나 호출하려는 구성 요소의 이름입니다. 후속 매개 변수는 구성 요소에 전달됩니다. InvokeAsync
는 임의 개수의 인수를 사용할 수 있습니다.
앱을 테스트합니다. 다음 이미지는 ToDo 목록 및 우선 순위 항목을 보여 줍니다.
또한 컨트롤러에서 보기 구성 요소를 직접 호출할 수도 있습니다.
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
보기 이름 지정
복잡한 보기 구성 요소에서는 조건에 따라 기본값이 아닌 보기를 지정해야 할 수도 있습니다. 다음 코드는 InvokeAsync
메서드에서 "PVC" 보기를 지정하는 방법을 보여 줍니다. PriorityListViewComponent
클래스에서 InvokeAsync
메서드를 수정합니다.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
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);
}
Views/Shared/Components/PriorityList/Default.cshtml
파일을 Views/Shared/Components/PriorityList/PVC.cshtml
보기에 복사합니다. PVC 보기가 사용되었음을 나타내는 제목을 추가합니다.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
다음과 같이 Views/ToDo/Index.cshtml
를 업데이트합니다.
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
앱을 실행하고 PVC 보기를 확인합니다.
PVC 보기가 렌더링되지 않는다면 우선 순위가 4 이상인 보기 구성 요소를 호출하고 있는지 확인해봅니다.
보기 경로 검토
우선 순위 보기가 반환되지 않도록 우선 순위 매개 변수를 3 이하로 변경합니다.
Views/ToDo/Components/PriorityList/Default.cshtml
의 이름을 일시적으로1Default.cshtml
로 바꿉니다.앱을 테스트하면 다음과 같은 오류가 발생합니다.
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml EnsureSuccessful
Views/ToDo/Components/PriorityList/1Default.cshtml
을Views/Shared/Components/PriorityList/Default.cshtml
에 복사합니다.Shared ToDo 보기 구성 요소 보기에 일부 태그를 추가하여 보기가 Shared 폴더에 있음을 표시합니다.
Shared 구성 요소 뷰를 테스트합니다.
하드 코드된 문자열 방지
컴파일 시간 안전성을 원하는 경우 하드 코드된 뷰 구성 요소 이름을 클래스 이름으로 바꿀 수 있습니다. "ViewComponent" 접미사 없이 보기 구성 요소를 만듭니다.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
using
문을 Razor 보기 파일에 추가하고 nameof
연산자를 사용합니다.
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo nameof</h2>
<!-- Markup removed for brevity. -->
<div>
@*
Note:
To use the below line, you need to #define no_suffix in ViewComponents/PriorityList.cs or it won't compile.
By doing so it will cause a problem to index as there will be multiple viewcomponents
with the same name after the compiler removes the suffix "ViewComponent"
*@
@*@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })*@
</div>
CLR 형식을 사용하는 Component.InvokeAsync
메서드의 오버로드를 사용할 수 있습니다. 이 경우 typeof
연산자를 사용해야 합니다.
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo typeof</h2>
<!-- Markup removed for brevity. -->
<div>
@await Component.InvokeAsync(typeof(PriorityListViewComponent), new { maxPriority = 4, isDone = true })
</div>
동기 작업 수행
비동기 작업을 수행할 필요가 없는 경우 프레임워크에서 동기 Invoke
메서드 호출을 처리합니다. 다음 메서드는 동기 Invoke
보기 구성 요소를 만듭니다.
public class PriorityList : ViewComponent
{
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var items = new List<string> { $"maxPriority: {maxPriority}", $"isDone: {isDone}" };
return View(items);
}
}
보기 구성 요소의 Razor 파일에는 Invoke
메서드(Views/Home/Components/PriorityList/Default.cshtml
)에 전달된 문자열이 나열됩니다.
@model List<string>
<h3>Priority Items</h3>
<ul>
@foreach (var item in Model)
{
<li>@item</li>
}
</ul>
보기 구성 요소는 다음 방법 중 하나를 사용하여 Razor 파일(예: Views/Home/Index.cshtml
)에서 호출됩니다.
IViewComponentHelper 접근 방법을 사용하려면 Component.InvokeAsync
를 호출합니다.
@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })
태그 도우미를 사용하려면 @addTagHelper
지시문을 사용하여 보기 구성 요소가 포함된 어셈블리를 등록합니다(보기 구성 요소는 MyWebApp
이라는 어셈블리에 있음).
@addTagHelper *, MyWebApp
Razor 태그 파일에서 보기 구성 요소 태그 도우미를 사용합니다.
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
PriorityList.Invoke
의 메서드 시그니처는 동기식이지만, Razor는 태그 파일에서 Component.InvokeAsync
를 사용하여 메서드를 찾고 호출합니다.
모든 뷰 구성 요소 매개 변수 필요
뷰 구성 요소의 각 매개 변수는 필수 특성입니다. 이 GitHub 문제를 참조하세요. 매개 변수를 하나라도 생략한 경우:
InvokeAsync
메서드 시그니처가 일치하지 않게 되므로 메서드가 실행되지 않습니다.- ViewComponent가 마크업을 렌더링하지 않습니다.
- 오류가 throw되지 않습니다.
추가 리소스
ASP.NET Core