다음을 통해 공유


마스터 페이지 및 부분을 사용하여 UI 재사용

작성자: Microsoft

PDF 다운로드

ASP.NET MVC 1을 사용하여 작지만 완전한 웹 애플리케이션을 빌드하는 방법을 안내하는 무료 "NerdDinner" 애플리케이션 자습서 의 7단계입니다.

7단계에서는 부분 보기 템플릿 및 master 페이지를 사용하여 뷰 템플릿 내에서 "DRY Principle"를 적용하여 코드 중복을 제거할 수 있는 방법을 살펴봅니다.

ASP.NET MVC 3을 사용하는 경우 MVC 3 또는 MVC Music Store 시작 따라가는 것이 좋습니다.

NerdDinner 7단계: 부분 및 마스터 페이지

MVC가 수용하는 ASP.NET 디자인 철학 중 하나는 "자신을 반복하지 마십시오" 원칙(일반적으로 "DRY"이라고 함)입니다. DRY 디자인은 코드 및 논리의 중복을 제거하는 데 도움이 되며, 궁극적으로 애플리케이션을 더 빠르게 빌드하고 유지 관리하기 쉽게 만듭니다.

여러 NerdDinner 시나리오에서 DRY 원칙이 적용된 것을 이미 살펴보았습니다. 몇 가지 예: 유효성 검사 논리는 모델 계층 내에서 구현되므로 컨트롤러에서 편집 및 만들기 시나리오에 적용할 수 있습니다. 편집, 세부 정보 및 삭제 작업 메서드에서 "NotFound" 보기 템플릿을 다시 사용하고 있습니다. 보기 템플릿과 함께 규칙 명명 패턴을 사용하므로 View() 도우미 메서드를 호출할 때 이름을 명시적으로 지정할 필요가 없습니다. 편집 및 만들기 작업 시나리오 모두에 DinnerFormViewModel 클래스를 다시 사용하고 있습니다.

이제 보기 템플릿 내에서 "DRY Principle"를 적용하여 코드 중복도 제거할 수 있는 방법을 살펴보겠습니다.

보기 템플릿 편집 및 만들기 다시 방문

현재 저녁 식사 양식 UI를 표시하기 위해 "Edit.aspx" 및 "Create.aspx"라는 두 가지 보기 템플릿을 사용하고 있습니다. 빠른 시각적 비교는 이러한 항목이 얼마나 유사한지 강조 표시합니다. 다음은 만들기 양식의 모양입니다.

내 M V C 애플리케이션 페이지의 스크린샷. 저녁 식사 호스트 양식이 표시됩니다.

"편집" 양식은 다음과 같습니다.

내 M V C 애플리케이션 페이지 스크린샷이 표시됩니다. 편집 양식이 표시됩니다.

큰 차이는 없나요? 제목 및 머리글 텍스트 외에 양식 레이아웃 및 입력 컨트롤은 동일합니다.

"Edit.aspx" 및 "Create.aspx" 뷰 템플릿을 열면 양식 레이아웃과 입력 컨트롤 코드가 동일한 것을 확인할 수 있습니다. 이 중복은 새 Dinner 속성을 도입하거나 변경할 때마다 두 번 변경해야 한다는 것을 의미합니다.

부분 보기 템플릿 사용

ASP.NET MVC는 페이지의 하위 부분에 대한 뷰 렌더링 논리를 캡슐화하는 데 사용할 수 있는 "부분 보기" 템플릿을 정의하는 기능을 지원합니다. "Partials"는 뷰 렌더링 논리를 한 번 정의한 다음 애플리케이션의 여러 위치에서 다시 사용하는 유용한 방법을 제공합니다.

Edit.aspx 및 Create.aspx 보기 템플릿 중복을 "DRY-up"하기 위해 두 항목 모두에 공통된 양식 레이아웃 및 입력 요소를 캡슐화하는 "DinnerForm.ascx"라는 부분 보기 템플릿을 만들 수 있습니다. /Views/Dinners 디렉터리를 마우스 오른쪽 단추로 클릭하고 "추가> 보기" 메뉴 명령을 선택하여 이 작업을 수행합니다.

솔루션 탐색기 탐색 트리의 스크린샷 저녁 식사가 강조 표시되어 있습니다. 추가 및 보기가 선택됩니다. 보기가 강조 표시됩니다.

그러면 "보기 추가" 대화 상자가 표시됩니다. "DinnerForm"을 만들려는 새 보기의 이름을 지정하고 대화 상자에서 "부분 보기 만들기" 확인란을 선택하고 DinnerFormViewModel 클래스를 전달함을 나타냅니다.

보기 추가 대화 상자의 스크린샷 부분 보기 만들기가 선택되고 강조 표시됩니다.

"추가" 단추를 클릭하면 Visual Studio에서 "\Views\Dinners" 디렉터리 내에서 새 "DinnerForm.ascx" 보기 템플릿을 만듭니다.

그런 다음 Edit.aspx/ Create.aspx 뷰 템플릿의 중복된 양식 레이아웃/입력 컨트롤 코드를 복사하여 새 "DinnerForm.ascx" 부분 보기 템플릿에 붙여넣을 수 있습니다.

<%= Html.ValidationSummary("Please correct the errors and try again.") %>

<% using (Html.BeginForm()) { %>

    <fieldset>
        <p>
            <label for="Title">Dinner Title:</label>
            <%= Html.TextBox("Title", Model.Dinner.Title) %>
            <%=Html.ValidationMessage("Title", "*") %>
        </p>
        <p>
            <label for="EventDate">Event Date:</label>
            <%= Html.TextBox("EventDate", Model.Dinner.EventDate) %>
            <%= Html.ValidationMessage("EventDate", "*") %>
        </p>
        <p>
            <label for="Description">Description:</label>
            <%= Html.TextArea("Description", Model.Dinner.Description) %>
            <%= Html.ValidationMessage("Description", "*") %>
        </p>
        <p>
            <label for="Address">Address:</label>
            <%= Html.TextBox("Address", Model.Dinner.Address) %>
            <%= Html.ValidationMessage("Address", "*") %>
        </p>
        <p>
            <label for="Country">Country:</label>
            <%= Html.DropDownList("Country", Model.Countries) %>                
            <%= Html.ValidationMessage("Country", "*") %>
        </p>
        <p>
            <label for="ContactPhone">Contact Phone #:</label>
            <%= Html.TextBox("ContactPhone", Model.Dinner.ContactPhone) %>
            <%= Html.ValidationMessage("ContactPhone", "*") %>
        </p>
            
        <p>
            <input type="submit" value="Save"/>
        </p>
    </fieldset>
    
<% } %>

그런 다음 편집 및 만들기 보기 템플릿을 업데이트하여 DinnerForm 부분 템플릿을 호출하고 양식 중복을 제거할 수 있습니다. 보기 템플릿 내에서 Html.RenderPartial("DinnerForm")을 호출하여 이 작업을 수행할 수 있습니다.

Create.aspx
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Host a Dinner
</asp:Content>

<asp:Content ID="Create" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Host a Dinner</h2>

    <% Html.RenderPartial("DinnerForm"); %>
    
</asp:Content>
Edit.aspx
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Edit: <%=Html.Encode(Model.Dinner.Title) %>
</asp:Content>

<asp:Content ID="Edit" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Edit Dinner</h2>

    <% Html.RenderPartial("DinnerForm"); %>

</asp:Content>

Html.RenderPartial을 호출할 때 원하는 부분 템플릿의 경로를 명시적으로 한정할 수 있습니다(예: ~Views/Dinners/DinnerForm.ascx"). 하지만 위의 코드에서는 ASP.NET MVC 내에서 규칙 기반 명명 패턴을 활용하고 렌더링할 부분의 이름으로 "DinnerForm"을 지정합니다. 이 ASP.NET MVC는 규칙 기반 뷰 디렉터리에서 먼저 표시됩니다(DinnersController의 경우 /Views/Dinners). 부분 템플릿을 찾을 수 없는 경우 /Views/Shared 디렉터리에서 해당 템플릿을 찾습니다.

부분 보기의 이름만 사용하여 Html.RenderPartial()을 호출하면 ASP.NET MVC는 호출 뷰 템플릿에서 사용하는 동일한 Model 및 ViewData 사전 개체를 부분 보기에 전달합니다. 또는 사용할 부분 보기에 대한 대체 Model 개체 및/또는 ViewData 사전을 전달할 수 있는 Html.RenderPartial()의 오버로드된 버전이 있습니다. 이는 전체 Model/ViewModel의 하위 집합만 전달하려는 시나리오에 유용합니다.

측면 항목: %= %>가 아닌 <%%>인 이유는 <무엇인가요?
위의 코드에서 알아차렸을 수 있는 미묘한 점 중 하나는 Html.RenderPartial()을 호출할 때 %= % 블록 대신 <% %> 블록을 사용 <> 한다는 것입니다. <%= ASP.NET %> 블록은 개발자가 지정된 값을 렌더링하려고 함을 나타냅니다(예: <%= "Hello" %> 는 "Hello"를 렌더링합니다). <%> 블록은 대신 개발자가 코드를 실행하려고 하며, 그 안에 렌더링된 모든 출력을 명시적으로 수행해야 함을 나타냅니다(예: <% Response.Write("Hello") %>. 위의 Html.RenderPartial 코드에서 % %> 블록을 사용하는 <이유는 Html.RenderPartial() 메서드가 문자열을 반환하지 않고 대신 호출 뷰 템플릿의 출력 스트림에 직접 콘텐츠를 출력하기 때문입니다. 성능 효율성상의 이유로 이 작업을 수행하므로 (잠재적으로 매우 큰) 임시 문자열 개체를 만들 필요가 없습니다. 이렇게 하면 메모리 사용량이 줄어들고 전체 애플리케이션 처리량이 향상됩니다. Html.RenderPartial()을 사용하는 경우 일반적인 실수 중 하나는 %> 블록 내에 있을 때 호출 끝에 세미콜론을 <추가하는 것을 잊어버리는 것입니다. 예를 들어 이 코드는 컴파일러 오류를 <발생합니다. % Html.RenderPartial("DinnerForm") %> 대신 작성해야 합니다. <% Html.RenderPartial("DinnerForm"); % %>> 블록은 <자체 포함된 코드 문이므로 C# 코드 문을 세미콜론으로 종료해야 합니다.

부분 보기 템플릿을 사용하여 코드 명확히 지정

여러 위치에서 뷰 렌더링 논리가 중복되지 않도록 "DinnerForm" 부분 보기 템플릿을 만들었습니다. 부분 보기 템플릿을 만드는 가장 일반적인 이유입니다.

한 곳에서만 호출되는 경우에도 부분 뷰를 만드는 것이 여전히 합리적일 수 있습니다. 보기 렌더링 논리가 추출되고 하나 이상의 잘 명명된 부분 템플릿으로 분할될 때 매우 복잡한 뷰 템플릿을 읽기가 훨씬 쉬워질 수 있습니다.

예를 들어 사이트에서 아래 코드 조각을 고려합니다. 프로젝트의 파일을 master(곧 살펴볼 예정). 코드는 읽기가 비교적 간단합니다. 화면 오른쪽 위에 로그인/로그아웃 링크를 표시하는 논리가 "LogOnUserControl" 부분 내에 캡슐화되어 있기 때문입니다.

<div id="header">
    <div id="title">
        <h1>My MVC Application</h1>
    </div>
      
    <div id="logindisplay">
        <% Html.RenderPartial("LogOnUserControl"); %>
    </div> 
    
    <div id="menucontainer">
    
        <ul id="menu">              
            <li><%=Html.ActionLink("Home", "Index", "Home")%></li>
            <li><%=Html.ActionLink("About", "About", "Home")%></li>
        </ul>
    </div>
</div>

보기 템플릿 내에서 html/code 태그를 이해하려고 혼동할 때마다 일부 태그가 추출되어 잘 명명된 부분 보기로 리팩터링된 경우 더 명확하지 않을지 여부를 고려합니다.

마스터 페이지

부분 보기를 지원하는 것 외에도 ASP.NET MVC는 사이트의 공통 레이아웃 및 최상위 html을 정의하는 데 사용할 수 있는 "master 페이지" 템플릿을 만드는 기능도 지원합니다. 그런 다음 콘텐츠 자리 표시자 컨트롤을 master 페이지에 추가하여 뷰별로 재정의되거나 "채워질 수 있는" 대체 가능한 지역을 식별할 수 있습니다. 이렇게 하면 애플리케이션 전체에 공통 레이아웃을 적용하는 매우 효과적인(및 DRY) 방법이 제공됩니다.

기본적으로 새 ASP.NET MVC 프로젝트에는 master 페이지 템플릿이 자동으로 추가됩니다. 이 master 페이지의 이름은 "Site.master"이며 \Views\Shared\ 폴더 내에 있습니다.

Nerd Dinner 탐색 트리의 스크린샷 사이트 마스터가 강조 표시되고 선택됩니다.

기본 사이트입니다. master 파일은 다음과 같습니다. 상단의 탐색 메뉴와 함께 사이트의 외부 html을 정의합니다. 여기에는 두 개의 대체 가능한 콘텐츠 자리 표시자 컨트롤이 포함됩니다. 하나는 제목에 대한 컨트롤이고 다른 하나는 페이지의 기본 콘텐츠를 교체해야 하는 위치입니다.

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">
    <title>
       <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
    </title>
   <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>

<body>
    <div class="page">

        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>
              
            <div id="logindisplay">
                <% Html.RenderPartial("LogOnUserControl"); %>
            </div> 
            
            <div id="menucontainer">

                <ul id="menu">              
                    <li><%=Html.ActionLink("Home", "Index", "Home")%></li>
                    <li><%=Html.ActionLink("About", "About", "Home")%></li>
                </ul>
            
            </div>
        </div>

        <div id="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server" />
        </div>
    </div>
</body>
</html>

NerdDinner 애플리케이션("목록", "세부 정보", "편집", "만들기", "NotFound" 등)에 대해 만든 모든 보기 템플릿은 이 사이트를 기반으로 합니다. master 템플릿. "보기 추가" 대화 상자를 사용하여 뷰를 만들 때 기본적으로 상위 <% @ 페이지 %> 지시문에 추가된 "MasterPageFile" 특성을 통해 표시됩니다.

<%@ Page Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerViewModel>" MasterPageFile="~/Views/Shared/Site.Master" %>

이 의미는 사이트를 변경할 수 있다는 것입니다. 콘텐츠를 master 보기 템플릿을 렌더링할 때 변경 내용이 자동으로 적용되고 사용됩니다.

사이트를 업데이트해 보겠습니다. 애플리케이션의 헤더가 "내 MVC 애플리케이션" 대신 "NerdDinner"가 되도록 master 헤더 섹션입니다. 또한 첫 번째 탭이 "저녁 식사 찾기"(HomeController의 Index() 작업 메서드에서 처리됨)이 되도록 탐색 메뉴를 업데이트하고 "저녁 식사 호스트"(DinnersController의 Create() 작업 방법으로 처리됨)라는 새 탭을 추가해 보겠습니다.

<div id="header">

    <div id="title">
        <h1>NerdDinner</h1>
    </div>

    <div id="logindisplay">
        <% Html.RenderPartial("LoginStatus"); %>
    </div> 
    
    <div id="menucontainer">
        <ul id="menu">      
           <li><%=Html.ActionLink("Find Dinner", "Index", "Home")%></li>
           <li><%=Html.ActionLink("Host Dinner", "Create", "Dinners")%></li>
           <li><%=Html.ActionLink("About", "About", "Home")%></li>   
        </ul>
    </div>
</div>

사이트를 저장할 때 파일을 master 브라우저를 새로 고치면 애플리케이션 내의 모든 보기에 헤더 변경 내용이 표시됩니다. 예:

괴상한 저녁 식사 예정 저녁 식사 목록 페이지의 스크린샷.

/Dinners/Edit/[id] URL을 사용하여 다음을 수행합니다.

Nerd Dinner 편집 양식 페이지의 스크린샷이 표시됩니다.

다음 단계

부분 및 master 페이지는 보기를 깔끔하게 구성할 수 있는 매우 유연한 옵션을 제공합니다. 콘텐츠/코드 보기가 중복되는 것을 방지하고 보기 템플릿을 더 쉽게 읽고 유지 관리할 수 있도록 도와줍니다.

이제 앞에서 빌드한 목록 시나리오를 다시 검토하고 확장 가능한 페이징 지원을 사용하도록 설정해 보겠습니다.