뷰: 부분 뷰

등록일시: 2016-10-10 08:00,  수정일시: 2016-10-26 22:27
조회수: 8,768
이 문서는 ASP.NET Core MVC 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
본문에서는 ASP.NET Core MVC의 부분 뷰 기능에 관해서 알아보고 간단한 예제를 살펴봅니다.

주의

이 페이지의 문서는 버전 1.0.0-rc2를 기준으로 작성되었으며, 아직 버전 1.0.0으로 갱신되지 않았습니다.

ASP.NET Core MVC는 부분 뷰 기능을 지원합니다. 서로 다른 뷰들 간에 공유하고자 하는 재사용 가능한 웹 페이지 영역이 존재할 때 부분 뷰를 사용하면 유용합니다.

GitHub에서 샘플 코드 확인 및 다운로드 받기

부분 뷰

부분 뷰(Partial View)는 다른 뷰의 내부에 렌더되는 뷰입니다. 부분 뷰가 실행되어 생성되는 HTML 출력은 부분 뷰를 호출한 뷰(부모 뷰)의 일부분으로 렌더됩니다. 일반적인 뷰와 마찬가지로 부분 뷰도 파일 확장자로 .cshtml 을 사용합니다.

노트

만약 ASP.NET 웹폼을 사용해본 경험이 있다면, 부분 뷰는 사용자 컨트롤(User Controls)과 비슷합니다.

부분 뷰를 사용해야 하는 경우

부분 뷰는 큰 뷰를 보다 작은 구성 요소들로 나눌 수 있는 효과적인 방법입니다. 부분 뷰를 사용하면 뷰 콘텐츠의 중복을 줄이고 뷰 요소를 재사용할 수 있습니다. 레이아웃과 관련된 공통적인 요소들은 _Layout.cshtml에서 지정하면 됩니다. 반면 레이아웃과 관련 없는 재사용가능한 콘텐츠는 부분 뷰를 이용해서 캡슐화 할 수 있습니다.

다수의 논리적 조각들로 구성되는 복잡한 페이지가 존재할 경우, 각 부분을 개별적인 부분 뷰로 분리해서 처리하면 작업에 도움이 됩니다. 페이지의 각 부분들을 페이지의 나머지 부분과 독립적인 뷰로 구성할 수 있고, 페이지 자체를 정의하는 뷰는 전반적인 페이지 구조와 부분 뷰를 렌더하기 위한 호출들만 포함하고 있으면 되기 때문에 매우 단순해집니다.

뷰에서도 중복배제(DRY, Don't Repeat Yourself)의 원칙을 준수하십시오.

부분 뷰 선언하기

부분 뷰도 일반적인 뷰와 동일한 방식으로 만들어지며, Views 폴더 하위에 .cshtml 파일을 만들면 됩니다. 부분 뷰와 일반적인 뷰 간에 의미론적 차이는 없으며, 단지 렌더되는 방식이 다를 뿐입니다. 컨트롤러의 ViewResult에서 직접 반환되는 기존 뷰를 그대로 부분 뷰로 사용할 수도 있습니다. 뷰와 부분 뷰가 렌더되는 방식에서 가장 큰 차이점은 부분 뷰의 경우 _ViewStart.cshtml 파일을 실행하지 않는다는 것입니다 (반면, 일반적인 뷰는 _ViewStart.cshtml 파일을 실행하는데, 이 파일에 대한 보다 자세한 내용은 레이아웃 문서를 참고하시기 바랍니다).

부분 뷰 참조하기

뷰 페이지 내부에서 부분 뷰를 렌더할 수 있는 방법에는 몇 가지가 있습니다. 가장 간단한 방법은 다음과 같이 IHtmlString 형식을 반환하는 Html.Partial HTML 헬퍼를 사용하는 것으로, @ 문자를 접두사로 사용하여 호출을 참조할 수 있습니다.

@Html.Partial("AuthorPartial")

또는 PartialAsync 메서드를 사용해서 비동기 코드를 포함한 부분 뷰를 렌더할 수도 있습니다 (일반적으로 뷰에 코드를 작성하는 것은 권장되지 않지만):

@await Html.PartialAsync("AuthorPartial")

그리고 RenderPartial HTML 헬퍼를 사용해서 부분 뷰를 렌더할 수도 있습니다. 다만, 이 메서드는 결과를 반환하지 않고 렌더된 출력을 응답 스트림에 직접 기록하기 때문에 Razor 코드 블럭 내부에서 호출돼야 합니다 (필요한 경우, RenderPartialAsync 메서드를 호출할 수도 있습니다):

@{
    Html.RenderPartial("AuthorPartial");
}

일부 시나리오에서는 RenderPartial 메서드나 RenderPartialAsync 메서드가 스트림에 직접 결과를 작성하기 때문에 성능이 더 우수할 수도 있습니다. 그러나 대부분은 Partial 메서드나 PartialAsync 메서드를 사용하는 것을 권장합니다.

노트

만약 뷰에서 코드를 실행해야 한다면, 부분 뷰 대신 뷰 구성 요소(View Component)를 사용하는 패턴이 권장됩니다.

부분 뷰 검색

부분 뷰를 참조할 때, 뷰의 위치를 지정할 수 있는 몇 가지 방법이 존재합니다:

// 지정한 이름을 가진 현재 폴더에 위치한 뷰를 사용합니다.
// 만약 해당하는 뷰를 찾기 못하면 이 이름으로 Shared 폴더에서 다시 검색을 시도합니다.
@Html.Partial("ViewName")

// 지정한 이름을 가진 현재 폴더에 위치한 뷰만 사용합니다.
@Html.Partial("ViewName.cshtml")

// 응용 프로그램 루트를 기준으로 뷰의 위치를 지정합니다.
// 경로는 응용 프로그램 루트를 의미하는 "/" 또는 "~/"로 시작합니다.
@Html.Partial("~/Views/Folder/ViewName.cshtml")
@Html.Partial("/Views/Folder/ViewName.cshtml")

// 상대 경로로 뷰의 위치를 지정합니다.
@Html.Partial("../Account/LoginPartial.cshtml")

필요한 경우, 서로 다른 뷰 폴더에 같은 이름을 가진 부분 뷰를 각각 만들 수 있습니다. 이름만 지정해서 뷰를 참조하면 (파일 확장자 없이), 각 폴더의 뷰들은 자신과 동일한 폴더에 존재하는 부분 뷰를 사용하게 됩니다. 그리고 Shared 폴더에 위치하는 기본 부분 뷰를 지정할 수도 있습니다. 이 부분 뷰는 부모 뷰가 자신의 폴더에서 부분 뷰의 자체 사본을 발견하지 못할 경우에 사용됩니다. 따라서 이 메커니즘을 활용하면, 부모 뷰와 같은 폴더에 존재하는 동일한 이름의 부분 뷰에 의해서 재정의되는 기본 부분 뷰를 (Shared 폴더에) 만들 수 있습니다.

부분 뷰는 반복적으로 연결될(Chained) 수 있습니다. 다시 말해서, 부분 뷰에서 다른 부분 뷰를 호출할 수도 있습니다 (순환 구조를 만들지 않는한). 이때, 각 뷰나 부분 뷰에서 상대적 경로를 사용하면, 항상 루트 뷰나 부모 뷰가 아닌 해당 뷰에 상대적인 경로가 사용됩니다.

노트

부분 뷰에 Razorsection을 선언하더라도 부모 뷰에는 나타나지 않습니다. 이는 부분 뷰에만 해당됩니다.

부분 뷰에서 데이터 접근하기

부분 뷰의 인스턴스가 만들어질 때, 부모 뷰의 ViewData 사전의 사본이 부분 뷰에 만들어집니다. 그리고 부분 뷰의 내부에서 이 데이터를 수정하더라도 부모 뷰의 데이터에는 반영이 되지 않습니다. 따라서 부분 뷰 내부에서 수행된 ViewData의 변경은 부분 뷰가 반환될 때 사라지게 됩니다.

대신, 부분 뷰에 ViewDataDictionary의 인스턴스를 전달할 수 있습니다:

@Html.Partial("PartialName", customViewData)

또는, 모델을 부분 뷰에 전달할 수도 있습니다. 여기서 모델은 페이지의 뷰 모델이거나, 뷰 모델의 일부분, 또는 사용자 지정 개체가 될 수도 있습니다. 간단히 Partial/PartialAsync HTML 헬퍼나 RenderPartial/RenderPartialAsync HTML 헬퍼를 호출할 때, 두 번째 매개변수로 모델을 전달하기만 하면 됩니다:

@Html.Partial("PartialName", viewModel)

부분 뷰에 ViewDataDictionary의 인스턴스와 뷰 모델을 동시에 전달할 수도 있습니다:

@Html.Partial("PartialName", viewModel, customViewData)

예제

다음 뷰는 Article 형식의 뷰 모델을 지정합니다. 이 Article 형식에는 AuthorPartial 이라는 부분 뷰에 전달되는 AuthorName 속성과, ArticleSection 형식을 렌더하는 ArticleSection 이라는 부분 뷰에 전달되는 (루프문 내에서) List<ArticleSection> 형식의 속성을 갖고 있습니다:

@using PartialViewsSample.ViewModels
@model Article

<h2>@Model.Title</h2>
@Html.Partial("AuthorPartial", Model.AuthorName)
@Model.PublicationDate

@foreach (var section in @Model.Sections)
{
    @Html.Partial("ArticleSection", section)
}

다음은 AuthorPartial 부분 뷰입니다 (/Views/Shared 폴더에 위치해 있습니다):

@model string
<div>
    <h3>@Model</h3>
    This partial view came from /Views/Shared/AuthorPartial.cshtml.<br/>
</div>

그리고 다음은 ArticleSection 부분 뷰입니다:

@using PartialViewsSample.ViewModels
@model ArticleSection

<h3>@Model.Title</h3>
<div>
    @Model.Content
</div>

부분 뷰들은 런타임 시에 부모 뷰 내부에 렌더되며, 부모 뷰에는 공유되는 _Layout.cshtml 이 적용됩니다. 예제 결과 페이지의 모습은 다음과 같습니다: