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"라는 두 가지 보기 템플릿을 사용하고 있습니다. 빠른 시각적 비교는 이러한 항목이 얼마나 유사한지 강조 표시합니다. 다음은 만들기 양식의 모양입니다.
"편집" 양식은 다음과 같습니다.
큰 차이는 없나요? 제목 및 머리글 텍스트 외에 양식 레이아웃 및 입력 컨트롤은 동일합니다.
"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\ 폴더 내에 있습니다.
기본 사이트입니다. 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을 사용하여 다음을 수행합니다.
다음 단계
부분 및 master 페이지는 보기를 깔끔하게 구성할 수 있는 매우 유연한 옵션을 제공합니다. 콘텐츠/코드 보기가 중복되는 것을 방지하고 보기 템플릿을 더 쉽게 읽고 유지 관리할 수 있도록 도와줍니다.
이제 앞에서 빌드한 목록 시나리오를 다시 검토하고 확장 가능한 페이징 지원을 사용하도록 설정해 보겠습니다.