다음을 통해 공유


컨트롤러 및 보기를 사용하여 목록/세부 정보 UI 구현

작성자: Microsoft

PDF 다운로드

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

4단계에서는 모델을 활용하는 애플리케이션에 컨트롤러를 추가하여 사용자에게 NerdDinner 사이트의 저녁 식사에 대한 데이터 목록/세부 정보 탐색 환경을 제공하는 방법을 보여 줍니다.

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

NerdDinner 4단계: 컨트롤러 및 뷰

기존 웹 프레임워크(클래식 ASP, PHP, ASP.NET Web Forms 등)를 사용하면 들어오는 URL이 일반적으로 디스크의 파일에 매핑됩니다. 예를 들어 "/Products.aspx" 또는 "/Products.php"와 같은 URL에 대한 요청은 "Products.aspx" 또는 "Products.php" 파일에서 처리될 수 있습니다.

웹 기반 MVC 프레임워크는 약간 다른 방식으로 URL을 서버 코드에 매핑합니다. 들어오는 URL을 파일에 매핑하는 대신 클래스의 메서드에 URL을 매핑합니다. 이러한 클래스는 "컨트롤러"라고 하며 들어오는 HTTP 요청을 처리하고, 사용자 입력을 처리하고, 데이터를 검색 및 저장하고, 클라이언트로 다시 보낼 응답을 결정합니다(HTML 표시, 파일 다운로드, 다른 URL로 리디렉션 등).

이제 NerdDinner 애플리케이션에 대한 기본 모델을 빌드했으므로 다음 단계는 컨트롤러를 사용하는 애플리케이션에 컨트롤러를 추가하여 사용자에게 당사 사이트의 Dinners에 대한 데이터 목록/세부 정보 탐색 환경을 제공하는 것입니다.

DinnersController 컨트롤러 추가

먼저 웹 프로젝트 내의 "컨트롤러" 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 컨트롤러 메뉴 명령을 선택합니다(Ctrl-M>, Ctrl-C를 입력하여 이 명령을 실행할 수도 있음).

Controllers 폴더와 추가 및 컨트롤러 메뉴 항목이 파란색으로 강조 표시된 솔루션 탐색기 창의 스크린샷

그러면 "컨트롤러 추가" 대화 상자가 표시됩니다.

Dinners 컨트롤러 텍스트로 채워진 컨트롤러 이름 필드를 보여 주는 컨트롤러 추가 대화 상자의 스크린샷

새 컨트롤러의 이름을 "DinnersController"로 지정하고 "추가" 단추를 클릭합니다. 그러면 Visual Studio에서 \Controllers 디렉터리 아래에 DinnersController.cs 파일을 추가합니다.

파란색으로 강조 표시된 Dinner Controllers dot c 파일을 보여 주는 솔루션 탐색기 창의 스크린샷

또한 코드 편집기 내에서 새 DinnersController 클래스가 열립니다.

DinnersController 클래스에 Index() 및 Details() 작업 메서드 추가

애플리케이션을 사용하여 방문자가 예정된 저녁 식사 목록을 찾아보고 목록에서 저녁 식사를 클릭하여 특정 세부 정보를 볼 수 있도록 허용하려고 합니다. 애플리케이션에서 다음 URL을 게시하여 이 작업을 수행합니다.

URL 용도
/저녁 식사/ 예정된 저녁 식사의 HTML 목록 표시
/Dinners/Details/[id] URL 내에 포함된 "id" 매개 변수로 표시된 특정 저녁 식사에 대한 세부 정보를 표시합니다. 이 매개 변수는 데이터베이스에서 저녁 식사의 DinnerID와 일치합니다. 예: /Dinners/Details/2는 DinnerID 값이 2인 Dinner에 대한 세부 정보가 포함된 HTML 페이지를 표시합니다.

아래와 같이 DinnersController 클래스에 두 개의 공용 "작업 메서드"를 추가하여 이러한 URL의 초기 구현을 게시합니다.

public class DinnersController : Controller {

    //
    // HTTP-GET: /Dinners/

    public void Index() {
        Response.Write("<h1>Coming Soon: Dinners</h1>");
    }

    //
    // HTTP-GET: /Dinners/Details/2

    public void Details(int id) {
        Response.Write("<h1>Details DinnerID: " + id + "</h1>");
    }
}

그런 다음 NerdDinner 애플리케이션을 실행하고 브라우저를 사용하여 호출합니다. "/Dinners/" URL을 입력하면 Index() 메서드가 실행되고 다음 응답이 다시 전송됩니다.

NerdDinner 애플리케이션을 실행하여 생성된 응답 창의 스크린샷. 곧 제공될 예정: 저녁 식사 텍스트를 보여 줍니다.

"/Dinners/Details/2" URL을 입력하면 Details() 메서드가 실행되고 다음 응답을 다시 보냅니다.

NerdDinner 애플리케이션을 실행하여 생성된 응답 창의 스크린샷- 세부 정보 저녁 식사 D: 2 텍스트를 보여 줌

ASP.NET MVC가 DinnersController 클래스를 만들고 이러한 메서드를 호출하는 것을 어떻게 알고 있었는지 궁금할 수 있습니다. 이를 이해하려면 라우팅의 작동 방식을 간단히 살펴보겠습니다.

ASP.NET MVC 라우팅 이해

ASP.NET MVC에는 URL이 컨트롤러 클래스에 매핑되는 방식을 제어하는 데 많은 유연성을 제공하는 강력한 URL 라우팅 엔진이 포함되어 있습니다. 이를 통해 ASP.NET 만들 컨트롤러 클래스를 선택하는 방법, 호출할 메서드를 완전히 사용자 지정할 수 있을 뿐만 아니라 URL/Querystring에서 변수를 자동으로 구문 분석하고 메서드에 매개 변수 인수로 전달할 수 있는 다양한 방법을 구성할 수 있습니다. SEO(검색 엔진 최적화)를 위해 사이트를 완전히 최적화하고 애플리케이션에서 원하는 URL 구조를 게시할 수 있는 유연성을 제공합니다.

기본적으로 새 ASP.NET MVC 프로젝트에는 미리 구성된 URL 라우팅 규칙 집합이 이미 등록되어 있습니다. 이렇게 하면 명시적으로 아무것도 구성하지 않고도 애플리케이션을 쉽게 시작할 수 있습니다. 기본 라우팅 규칙 등록은 프로젝트의 "애플리케이션" 클래스 내에서 찾을 수 있으며, 프로젝트의 루트에서 "Global.asax" 파일을 두 번 클릭하여 열 수 있습니다.

파란색으로 강조 표시되고 빨간색 원을 그리는 x 파일의 전역 점을 보여 주는 솔루션 탐색기 창의 스크린샷

기본 ASP.NET MVC 라우팅 규칙은 이 클래스의 "RegisterRoutes" 메서드 내에 등록됩니다.

public void RegisterRoutes(RouteCollection routes) {

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                       // Route name
        "{controller}/{action}/{id}",                    // URL w/ params
        new { controller="Home", action="Index",id="" }  // Param defaults
    );
}

"경로입니다. 위의 MapRoute()" 메서드 호출은 URL 형식을 사용하여 들어오는 URL을 컨트롤러 클래스에 매핑하는 기본 라우팅 규칙을 등록합니다. "/{controller}/{action}/{id}" - 여기서 "controller"는 인스턴스화할 컨트롤러 클래스의 이름이고, "action"은 호출할 공용 메서드의 이름이며, "id"는 메서드에 인수로 전달될 수 있는 URL 내에 포함된 선택적 매개 변수입니다. "MapRoute()" 메서드 호출에 전달된 세 번째 매개 변수는 URL에 없는 경우 컨트롤러/작업/ID 값에 사용할 기본값 집합입니다(컨트롤러 = "Home", Action="Index", Id=").

다음은 기본 "/{controllers}/{action}/{id}"경로 규칙을 사용하여 다양한 URL을 매핑하는 방법을 보여 주는 표입니다.

URL 컨트롤러 클래스 작업 방법 전달된 매개 변수
/Dinners/Details/2 DinnersController Details(id) id=2
/Dinners/Edit/5 DinnersController Edit(id) id=5
/Dinners/Create DinnersController Create() 해당 없음
/저녁 식사 DinnersController Index() 해당 없음
/홈 HomeController Index() 해당 없음
/ HomeController Index() 해당 없음

마지막 세 행에는 사용 중인 기본값(컨트롤러 = 홈, 작업 = 인덱스, ID = "")이 표시됩니다. "Index" 메서드가 지정되지 않은 경우 기본 작업 이름으로 등록되므로 "/Dinners" 및 "/Home" URL로 인해 Controller 클래스에서 Index() 작업 메서드가 호출됩니다. "Home" 컨트롤러가 지정되지 않은 경우 기본 컨트롤러로 등록되므로 "/" URL을 사용하면 HomeController가 생성되고 해당 컨트롤러의 Index() 작업 메서드가 호출됩니다.

이러한 기본 URL 라우팅 규칙이 마음에 들지 않으면 변경하기 쉽다는 것입니다. 위의 RegisterRoutes 메서드 내에서 편집하기만 하면 됩니다. 하지만 NerdDinner 애플리케이션의 경우 기본 URL 라우팅 규칙을 변경하지 않고 그대로 사용합니다.

DinnersController의 DinnerRepository 사용

이제 DinnersController의 Index() 및 Details() 작업 메서드의 현재 구현을 모델을 사용하는 구현으로 바꾸겠습니다.

앞에서 빌드한 DinnerRepository 클래스를 사용하여 동작을 구현합니다. 먼저 "NerdDinner.Models" 네임스페이스를 참조하는 "using" 문을 추가한 다음 DinnerRepository의 instance DinnerController 클래스의 필드로 선언합니다.

이 챕터의 뒷부분에서는 "종속성 주입"이라는 개념을 소개하고 컨트롤러가 더 나은 단위 테스트를 가능하게 하는 DinnerRepository에 대한 참조를 얻을 수 있는 또 다른 방법을 보여 주지만 지금은 아래와 같이 DinnerRepository 인라인의 instance 만듭니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NerdDinner.Models;

namespace NerdDinner.Controllers {

    public class DinnersController : Controller {

        DinnerRepository dinnerRepository = new DinnerRepository();

        //
        // GET: /Dinners/

        public void Index() {
            var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        }

        //
        // GET: /Dinners/Details/2

        public void Details(int id) {
            Dinner dinner = dinnerRepository.GetDinner(id);
        }
    }
}

이제 검색된 데이터 모델 개체를 사용하여 HTML 응답을 다시 생성할 준비가 되었습니다.

컨트롤러와 함께 보기 사용

작업 메서드 내에서 코드를 작성하여 HTML을 어셈블한 다음 Response.Write() 도우미 메서드를 사용하여 클라이언트로 다시 보낼 수 있지만 해당 접근 방식은 상당히 다루기 어려워집니다. 훨씬 더 나은 방법은 DinnersController 작업 메서드 내에서만 애플리케이션 및 데이터 논리를 수행하고 HTML 표현을 출력하는 별도의 "보기" 템플릿에 HTML 응답을 렌더링하는 데 필요한 데이터를 전달하는 것입니다. 잠시 후에 볼 수 있듯이 "보기" 템플릿은 일반적으로 HTML 태그와 포함된 렌더링 코드의 조합을 포함하는 텍스트 파일입니다.

컨트롤러 논리를 뷰 렌더링과 분리하면 몇 가지 큰 이점이 있습니다. 특히 애플리케이션 코드와 UI 서식/렌더링 코드 간에 명확한 "문제 분리"를 적용하는 데 도움이 됩니다. 이렇게 하면 UI 렌더링 논리에서 격리된 애플리케이션 논리를 훨씬 쉽게 단위 테스트할 수 있습니다. 나중에 애플리케이션 코드를 변경하지 않고도 UI 렌더링 템플릿을 더 쉽게 수정할 수 있습니다. 또한 개발자와 디자이너가 프로젝트에서 더 쉽게 공동 작업할 수 있습니다.

DinnersController 클래스를 업데이트하여 두 작업 메서드의 메서드 시그니처를 반환 형식 "void"에서 "ActionResult"의 반환 형식으로 변경하여 뷰 템플릿을 사용하여 HTML UI 응답을 다시 보내려고 함을 나타낼 수 있습니다. 그런 다음 컨트롤러 기본 클래스에서 View() 도우미 메서드를 호출하여 아래와 같은 "ViewResult" 개체를 다시 반환할 수 있습니다.

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View("Index", dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }
}

위에서 사용하는 View() 도우미 메서드의 서명은 다음과 같습니다.

결과 보기 보기(문자열 보기 이름, 개체 모델) 텍스트가 있는 View 도우미 메서드의 스크린샷

View() 도우미 메서드의 첫 번째 매개 변수는 HTML 응답을 렌더링하는 데 사용할 뷰 템플릿 파일의 이름입니다. 두 번째 매개 변수는 HTML 응답을 렌더링하기 위해 뷰 템플릿에 필요한 데이터를 포함하는 모델 개체입니다.

Index() 작업 메서드 내에서 View() 도우미 메서드를 호출하고 "인덱스" 뷰 템플릿을 사용하여 저녁 식사의 HTML 목록을 렌더링하려고 함을 나타냅니다. 뷰 템플릿에 Dinner 개체 시퀀스를 전달하여 목록을 생성합니다.

//
    // GET: /Dinners/

    public ActionResult Index() {
    
        var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        
        return View("Index", dinners);
    }

Details() 작업 메서드 내에서 URL 내에 제공된 ID를 사용하여 Dinner 개체를 검색하려고 합니다. 유효한 Dinner가 발견되면 View() 도우미 메서드를 호출합니다. 이 메서드는 "세부 정보" 뷰 템플릿을 사용하여 검색된 Dinner 개체를 렌더링하려고 함을 나타냅니다. 잘못된 저녁 식사가 요청되면 "NotFound" 뷰 템플릿(및 템플릿 이름만 사용하는 View() 도우미 메서드의 오버로드된 버전을 사용하여 Dinner가 존재하지 않음을 나타내는 유용한 오류 메시지를 렌더링합니다.

//
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.FindDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }

이제 "NotFound", "Details" 및 "Index" 보기 템플릿을 구현해 보겠습니다.

"NotFound" 뷰 템플릿 구현

먼저 요청된 저녁 식사를 찾을 수 없음을 나타내는 친숙한 오류 메시지를 표시하는 "NotFound" 보기 템플릿을 구현합니다.

컨트롤러 작업 메서드 내에 텍스트 커서를 배치하여 새 보기 템플릿을 만든 다음 마우스 오른쪽 단추를 클릭하고 "보기 추가" 메뉴 명령을 선택합니다(Ctrl-M, Ctrl-V를 입력하여 이 명령을 실행할 수도 있음).

오른쪽 클릭 메뉴 항목 보기 추가가 파란색으로 강조 표시되고 빨간색 원을 그리는 프로젝트의 스크린샷

그러면 아래와 같이 "보기 추가" 대화 상자가 표시됩니다. 기본적으로 대화 상자는 대화가 시작될 때 커서가 있던 작업 메서드의 이름과 일치하도록 만들 뷰의 이름을 미리 채웁니다(이 경우 "세부 정보"). 먼저 "NotFound" 템플릿을 구현하려고 하므로 이 보기 이름을 재정의하고 대신 "NotFound"로 설정합니다.

보기 이름 필드가 찾을 수 없음으로 설정된 보기 추가 창의 스크린샷, master 선택 페이지 상자가 선택되고 콘텐츠 장소 소유자 ID가 기본 콘텐츠로 설정됩니다.

"추가" 단추를 클릭하면 Visual Studio에서 "\Views\Dinners" 디렉터리 내에서 새 "NotFound.aspx" 보기 템플릿을 만듭니다(디렉터리가 아직 없는 경우에도 생성됨).

찾을 수 없음 점의 p x 파일이 파란색으로 강조 표시된 솔루션 탐색기 창 폴더 계층 구조의 스크린샷

또한 코드 편집기 내에서 새로운 "NotFound.aspx" 보기 템플릿이 열립니다.

코드 편집기 내에서 p x 파일이 열려 있는 찾을 수 없음 점이 있는 코드 편집기 창의 스크린샷

기본적으로 보기 템플릿에는 콘텐츠와 코드를 추가할 수 있는 두 개의 "콘텐츠 영역"이 있습니다. 첫 번째 를 사용하면 다시 전송된 HTML 페이지의 "제목"을 사용자 지정할 수 있습니다. 두 번째 를 사용하면 다시 전송된 HTML 페이지의 "기본 콘텐츠"를 사용자 지정할 수 있습니다.

"NotFound" 보기 템플릿을 구현하려면 몇 가지 기본 콘텐츠를 추가합니다.

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner Not Found
</asp:Content>

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

    <h2>Dinner Not Found</h2>

    <p>Sorry - but the dinner you requested doesn't exist or was deleted.</p>

</asp:Content>

그런 다음 브라우저 내에서 사용해 보세요. 이렇게 하려면 "/Dinners/Details/9999" URL을 요청해 보겠습니다. 이는 현재 데이터베이스에 없는 저녁 식사를 참조하며 DinnersController.Details() 작업 메서드가 "NotFound" 보기 템플릿을 렌더링하게 합니다.

주소 상자에 /Dinners/Details/9999 U R L이 빨간색으로 둥글게 표시된 내 MVC 애플리케이션 창의 스크린샷

위의 스크린샷에서 알 수 있는 한 가지는 기본 보기 템플릿이 화면의 기본 콘텐츠를 둘러싸는 많은 HTML을 상속했다는 것입니다. 이는 보기 템플릿이 사이트의 모든 보기에 일관된 레이아웃을 적용할 수 있는 "master 페이지" 템플릿을 사용하기 때문입니다. 이 자습서의 뒷부분에서 master 페이지가 더 많이 작동하는 방법에 대해 설명합니다.

"세부 정보" 보기 템플릿 구현

이제 단일 Dinner 모델에 대한 HTML을 생성하는 "세부 정보" 보기 템플릿을 구현해 보겠습니다.

세부 정보 작업 메서드 내에 텍스트 커서를 배치한 다음 마우스 오른쪽 단추를 클릭하고 "보기 추가" 메뉴 명령을 선택하거나 Ctrl-M, Ctrl-V를 눌러 이 작업을 수행합니다.

오른쪽 클릭 메뉴 항목 추가 보기 점 점 점이 빨간색으로 강조 표시된 코드 편집기 창의 스크린샷

그러면 "보기 추가" 대화 상자가 표시됩니다. 기본 보기 이름("세부 정보")을 유지합니다. 또한 대화 상자에서 "강력한 형식의 보기 만들기" 확인란을 선택하고 컨트롤러에서 보기로 전달하는 모델 형식의 이름을 선택합니다(콤보 상자 드롭다운 사용). 이 보기에서는 Dinner 개체를 전달합니다(이 형식의 정규화된 이름은 "NerdDinner.Models.Dinner").

콘텐츠 보기 드롭다운이 세부 정보로 설정되고 데이터 클래스 보기가 Nerd Dinner dot Models dot Dinner로 설정된 보기 추가 창의 스크린샷

"빈 보기"를 만들기로 선택한 이전 템플릿과 달리 이번에는 "세부 정보" 템플릿을 사용하여 보기를 자동으로 "스캐폴드"하도록 선택합니다. 위의 대화 상자에서 "콘텐츠 보기" 드롭다운을 변경하여 이를 나타낼 수 있습니다.

"스캐폴딩"은 전달하려는 Dinner 개체를 기반으로 세부 정보 보기 템플릿의 초기 구현을 생성합니다. 이렇게 하면 보기 템플릿 구현을 빠르게 시작할 수 있는 쉬운 방법이 제공됩니다.

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

Dinners 폴더가 파란색으로 강조 표시된 폴더 계층 구조를 보여 주는 솔루션 탐색기 창의 스크린샷

또한 코드 편집기 내에서 새 "Details.aspx" 보기 템플릿이 열립니다. Dinner 모델을 기반으로 하는 세부 정보 보기의 초기 스캐폴드 구현이 포함됩니다. 스캐폴딩 엔진은 .NET 리플렉션을 사용하여 전달된 클래스에 노출된 공용 속성을 확인하고, 찾은 각 형식에 따라 적절한 콘텐츠를 추가합니다.

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Details
</asp:Content>

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

    <h2>Details</h2>

    <fieldset>
        <legend>Fields</legend>
        <p>
            DinnerID:
            <%=Html.Encode(Model.DinnerID) %>
        </p>
        <p>
            Title:
            <%=Html.Encode(Model.Title) %>
        </p>
        <p>
            EventDate:
            <%= Html.Encode(String.Format("{0:g}", Model.EventDate)) %>
        </p>
        <p>
            Description:
            <%=Html.Encode(Model.Description) %>
        </p>
        <p>
            HostedBy:
            <%=Html.Encode(Model.HostedBy) %>
        </p>
        <p>
            ContactPhone:
            <%=Html.Encode(Model.ContactPhone) %>
        </p>
        <p>
            Address:
            <%=Html.Encode(Model.Address) %>
        </p>
        <p>
            Country:
            <%=Html.Encode(Model.Country) %>
        </p>
        <p>
            Latitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Latitude)) %>
        </p>
        <p>
            Longitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Longitude)) %>
        </p>
    </fieldset>
    
    <p>
        <%=Html.ActionLink("Edit","Edit", new { id=Model.DinnerID }) %>|
        <%=Html.ActionLink("Back to List", "Index") %>
    </p>
    
</asp:Content>

"/Dinners/Details/1" URL을 요청하여 브라우저에서 이 "세부 정보" 스캐폴드 구현이 어떻게 표시되는지 확인할 수 있습니다. 이 URL을 사용하면 처음 만들 때 데이터베이스에 수동으로 추가한 저녁 식사 중 하나가 표시됩니다.

주소 상자에 빨간색으로 원을 그리는 / 저녁 식사 / 세부 정보 / 1 U R L을 보여주는 애플리케이션 응답 창의 스크린샷.

이렇게 하면 빠르게 실행되고 Details.aspx 뷰의 초기 구현이 제공됩니다. 그런 다음, 이동하여 조정하여 만족도에 맞게 UI를 사용자 지정할 수 있습니다.

Details.aspx 템플릿을 좀 더 자세히 살펴보면 포함된 렌더링 코드뿐만 아니라 정적 HTML도 포함되어 있음을 알 수 있습니다. <% %> 코드 너겟은 뷰 템플릿이 렌더링 <될 때 코드를 실행하고 % = %> 코드 너겟은 그 안에 포함된 코드를 실행한 다음 결과를 템플릿의 출력 스트림으로 렌더링합니다.

강력한 형식의 "Model" 속성을 사용하여 컨트롤러에서 전달된 "Dinner" 모델 개체에 액세스하는 코드를 View 내에 작성할 수 있습니다. Visual Studio는 편집기 내에서 이 "모델" 속성에 액세스할 때 전체 코드 intellisense를 제공합니다.

설명 항목이 파란색으로 강조 표시된 드롭다운 목록을 보여 주는 코드 편집기 창의 스크린샷

최종 세부 정보 보기 템플릿의 원본이 아래와 같이 표시되도록 몇 가지 조정을 수행해 보겠습니다.

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

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

    <h2><%=Html.Encode(Model.Title) %></h2>
    <p>
        <strong>When:</strong> 
        <%=Model.EventDate.ToShortDateString() %> 

        <strong>@</strong>
        <%=Model.EventDate.ToShortTimeString() %>
    </p>
    <p>
        <strong>Where:</strong> 
        <%=Html.Encode(Model.Address) %>,
        <%=Html.Encode(Model.Country) %>
    </p>
     <p>
        <strong>Description:</strong> 
        <%=Html.Encode(Model.Description) %>
    </p>       
    <p>
        <strong>Organizer:</strong> 
        <%=Html.Encode(Model.HostedBy) %>
        (<%=Html.Encode(Model.ContactPhone) %>)
    </p>
    
    <%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID })%> |
    <%= Html.ActionLink("Delete Dinner","Delete", new { id=Model.DinnerID})%>   
     
</asp:Content>

"/Dinners/Details/1" URL에 다시 액세스하면 이제 아래와 같이 렌더링됩니다.

점 NET 선물 보기의 새 스타일화를 보여 주는 애플리케이션 응답 창의 스크린샷

"인덱스" 뷰 템플릿 구현

이제 예정된 저녁 식사 목록을 생성하는 "인덱스" 보기 템플릿을 구현해 보겠습니다. 이렇게 하려면 인덱스 작업 메서드 내에 텍스트 커서를 배치한 다음 마우스 오른쪽 단추를 클릭하고 "보기 추가" 메뉴 명령을 선택합니다(또는 Ctrl-M, Ctrl-V를 누릅니다).

"보기 추가" 대화 상자 내에서 "인덱스"라는 보기 템플릿을 유지하고 "강력한 형식의 보기 만들기" 확인란을 선택합니다. 이번에는 "목록" 뷰 템플릿을 자동으로 생성하도록 선택하고 보기에 전달된 모델 형식으로 "NerdDinner.Models.Dinner"를 선택합니다("목록" 스캐폴드를 만들고 있음을 나타내기 때문에 보기 추가 대화 상자에서 컨트롤러에서 보기로 Dinner 개체 시퀀스를 전달하고 있다고 가정합니다).

보기 이름이 인덱스로 설정된 보기 추가 창의 스크린샷, 강력한 형식의 보기 만들기 상자가 선택되고 master 선택 페이지 상자가 선택됩니다.

"추가" 단추를 클릭하면 Visual Studio에서 "\Views\Dinners" 디렉터리 내에서 새 "Index.aspx" 보기 템플릿 파일을 만듭니다. 뷰에 전달하는 Dinners의 HTML 테이블 목록을 제공하는 초기 구현을 "스캐폴드"합니다.

애플리케이션을 실행하고 "/Dinners/" URL에 액세스하면 다음과 같이 저녁 식사 목록이 렌더링됩니다.

보기 추가 업데이트 후 그리드 레이아웃의 저녁 식사 목록을 보여 주는 애플리케이션 응답 창의 스크린샷.

위의 테이블 솔루션은 저녁 식사 데이터의 그리드와 유사한 레이아웃을 제공합니다. 이는 소비자가 저녁 식사 목록에 대해 원하는 것과는 다릅니다. Index.aspx 뷰 템플릿을 업데이트하고 수정하여 더 적은 수의 데이터 열을 나열하고 ul> 요소를 사용하여 <아래 코드를 사용하여 테이블 대신 렌더링할 수 있습니다.

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

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>                 
                <%=Html.Encode(dinner.Title) %>            
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
    
</asp:Content>

모델의 각 저녁 식사를 반복하면서 위의 foreach 문 내에서 "var" 키워드(keyword) 사용하고 있습니다. C# 3.0에 익숙하지 않은 사람들은 "var"을 사용하면 저녁 식사 개체가 늦게 바인딩된다는 것을 의미합니다. 대신 컴파일러가 강력한 형식의 "Model" 속성("IEnumerable<Dinner" 형식)에 대해 형식 유추를 사용하고 로컬 "dinner>" 변수를 Dinner 형식으로 컴파일한다는 것을 의미합니다. 즉, 코드 블록 내에서 전체 intellisense 및 컴파일 시간 검사를 받습니다.

회색 점선 상자에서 주소 목록 항목이 강조 표시된 드롭다운 메뉴를 보여 주는 코드 편집기 창의 스크린샷

브라우저의 /Dinners URL에서 새로 고침을 누르면 업데이트된 보기는 다음과 같습니다.

새로 고침 명령 후 예정된 저녁 식사 목록을 보여 주는 애플리케이션 응답 창의 스크린샷.

이것은 더 나은 찾고 있습니다 – 그러나 완전히 아직 거기 있지 않습니다. 마지막 단계는 최종 사용자가 목록에서 개별 저녁 식사를 클릭하고 세부 정보를 볼 수 있도록 하는 것입니다. DinnersController의 Details 작업 메서드에 연결되는 HTML 하이퍼링크 요소를 렌더링하여 이를 구현합니다.

두 가지 방법 중 하나로 인덱스 보기 내에서 이러한 하이퍼링크를 생성할 수 있습니다. 첫 번째는 HTML <> 요소 내에 <% %> 블록을 포함하는 <아래와 같은 요소를 HTML에> 수동으로 만드는 것입니다.

클래스 및 백분율 블록 텍스트가 강조 표시되고 빨간색 원을 그리는 코드 편집기 창의 스크린샷

사용할 수 있는 다른 방법은 프로그래밍 방식으로 HTML을 만드는 것을 지원하는 ASP.NET MVC 내의 기본 제공 "Html.ActionLink()" 도우미 메서드를 활용하여 컨트롤러의 다른 작업 메서드에 연결되는 요소를 만드는 <> 것입니다.

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

Html.ActionLink() 도우미 메서드의 첫 번째 매개 변수는 표시할 링크 텍스트(이 경우 저녁 식사의 제목)이며, 두 번째 매개 변수는 링크를 생성하려는 컨트롤러 작업 이름(이 경우 Details 메서드)이며, 세 번째 매개 변수는 작업에 보낼 매개 변수 집합입니다(속성 이름/값이 있는 익명 형식으로 구현됨). 이 경우 연결하려는 저녁 식사의 "id" 매개 변수를 지정하고 ASP.NET MVC의 기본 URL 라우팅 규칙은 "{Controller}/{Action}/{id}"이므로 Html.ActionLink() 도우미 메서드는 다음 출력을 생성합니다.

<a href="/Dinners/Details/1">.NET Futures</a>

Index.aspx 보기의 경우 Html.ActionLink() 도우미 메서드 접근 방식을 사용하고 목록 링크의 각 저녁 식사를 적절한 세부 정보 URL에 연결합니다.

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Upcoming Dinners
</asp:Content>

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

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>     
                <%=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
</asp:Content>

이제 /Dinners URL에 도달하면 저녁 식사 목록은 다음과 같습니다.

목록 항목에 해당하는 새 링크가 있는 예정된 저녁 식사 목록을 보여 주는 애플리케이션 응답 창의 스크린샷.

목록에서 저녁 식사를 클릭하면 세부 정보를 확인합니다.

선택한 목록 항목과 데이터베이스에 입력한 항목에 해당하는 세부 정보를 보여 주는 애플리케이션 응답 창의 스크린샷

규칙 기반 명명 및 \Views 디렉터리 구조

ASP.NET MVC 애플리케이션은 기본적으로 보기 템플릿을 확인할 때 규칙 기반 디렉터리 명명 구조를 사용합니다. 이를 통해 개발자는 컨트롤러 클래스 내에서 보기를 참조할 때 위치 경로를 완전히 정규화할 필요가 없습니다. 기본적으로 ASP.NET MVC는 애플리케이션 아래의 *\Views[ControllerName]* 디렉터리 내에서 보기 템플릿 파일을 찾습니다.

예를 들어 DinnersController 클래스에서는 세 가지 보기 템플릿인 "Index", "Details" 및 "NotFound"를 명시적으로 참조합니다. ASP.NET MVC는 기본적으로 애플리케이션 루트 디렉터리 아래 의 \Views\Dinners 디렉터리 내에서 이러한 보기를 찾습니다.

Dinners 폴더가 파란색 사각형으로 강조 표시된 폴더 계층 구조를 보여 주는 솔루션 탐색기 창의 스크린샷

프로젝트 내에 현재 세 개의 컨트롤러 클래스(DinnersController, HomeController 및 AccountController - 프로젝트를 만들 때 기본적으로 추가된 마지막 두 개) 및 \Views 디렉터리 내에 세 개의 하위 디렉터리(각 컨트롤러에 대해 하나씩)가 있는 방법을 확인합니다.

홈 및 계정 컨트롤러에서 참조되는 보기는 해당 \Views\Home 및 \Views\Account 디렉터리에서 해당 보기 템플릿을 자동으로 resolve. \Views\Shared 하위 디렉터리를 사용하면 애플리케이션 내의 여러 컨트롤러에서 다시 사용되는 보기 템플릿을 저장할 수 있습니다. ASP.NET MVC가 뷰 템플릿을 resolve 시도하면 먼저 \Views[Controller] 특정 디렉터리 내에서 검사, 보기 템플릿을 찾을 수 없으면 \Views\Shared 디렉터리 내에서 표시됩니다.

개별 보기 템플릿의 이름을 지정할 때 권장되는 지침은 뷰 템플릿이 렌더링을 발생시킨 작업 메서드와 동일한 이름을 공유하도록 하는 것입니다. 예를 들어 위의 "Index" 작업 메서드는 "Index" 뷰를 사용하여 뷰 결과를 렌더링하고 "Details" 작업 메서드는 "세부 정보" 뷰를 사용하여 결과를 렌더링합니다. 이렇게 하면 각 작업과 연결된 템플릿을 쉽게 확인할 수 있습니다.

뷰 템플릿의 이름이 컨트롤러에서 호출되는 작업 메서드와 동일한 경우 개발자는 뷰 템플릿 이름을 명시적으로 지정할 필요가 없습니다. 대신 모델 개체를 "View()" 도우미 메서드에 전달할 수 있으며(보기 이름을 지정하지 않고) ASP.NET MVC는 디스크에서 \Views[ControllerName][ActionName] 보기 템플릿을 사용하여 렌더링하려는 것을 자동으로 유추합니다.

이렇게 하면 컨트롤러 코드를 약간 클린 코드에서 이름이 두 번 중복되는 것을 방지할 수 있습니다.

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View(dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }
}

위의 코드는 사이트에 대한 좋은 저녁 식사 목록 / 세부 정보 환경을 구현하는 데 필요한 모든 것입니다.

다음 단계

이제 멋진 저녁 식사 브라우징 환경이 구축되었습니다.

이제 CRUD(만들기, 읽기, 업데이트, 삭제) 데이터 양식 편집 지원을 사용하도록 설정합니다.