|
Steven Sanderson의 저서 Professional Asp.Net MVC 1(장현희 옮김) 그리고 MVC 2 (원서)를 공부하면서 최근에 발표된 MVC 3와 차이점을 비교 학습을 진행합니다.
MVC의 장점이 어디에 있고 MVC 1, 2, 3은 어떠한 변화를 가져왔는지? 어떻게 시작해야 할지 등을 생각해 볼까 합니다.
-------------------------------------------------------------------------------------
MVC 3에서 컨트롤러에 대한 많은 변화가 있습니다. Scaffolding과 Razor 구문 등 아직 정규화된 문서가 많지 않고 너무 복잡하여 일단 건너 띄고 MVC 1, 2에 기술되어 있는 내용을 배웁니다.
기존의 웹프레임워크 요청된 Url를 주로 서버상의 디스크에 저장된 파일과 매칭되었다. 그러나 MVC 프레임워크는 Url을 서버측 코드로 매핑한다. 이러한 방법은 요청된 Url을 파일에 매핑하지 않고 특정클레스 즉, 컨트롤러 클레스에 매핑한다. 컨트롤러 클레스는 Http 요청을 수행하고 사용자의 입력을 처리하며, 데이터를 조회하거나 저장하고 클라이언트에 되돌려 줄 반환 Html를 표시하거나 다른 URL로의 이동 또는 파일의 다운로드 등)을 결정한다.
1. DinnersController class 추가
MVC 3의 Scaffolding 부분은 건너 띄고 다음과 같이 빈 컨트롤러를 생성합니다.
컨틀로러 폴더에서 오른쪽 마우스를 누르고 추가를 누르면 아래 그림과 같은 창이 뜨고, 여기에 이름을 "DinnersControl"로 써줍니다. 이때 Controller의 이름 규칙에서 중요한 것은 이름이 반드시 _Controller로 끝이나야 합니다.
다음과 같은 초기화면이 생성됩니다.
테스트를 하기 위해 기존의 puplic ActionResult()를 마킹하고 아래와 같이 Response.Write()구문을 사용합니다.
"F5"를 눌러 실행시킨 결과 화면의 주소창에 /Dinners를 입력한 결과창 입니다.
화면의 주소창에 /Dinners/2를 입력한 결과창 입니다.
이와 같은 결과는 MVC 프레임워크의 라우팅 특성입니다.
2. ASP.NET MVC URL 라우팅
MVC는 URL를 컨트롤하고 클래스와 유연하게 연결할 수 있는 강력한 IRL 라우팅 엔진을 내장하고 있습니다.(기종의 ASP.NET 웹 폼 환경에서도 사용이 가능함) 이 URL 라우팅 엔진을 활용하면 ASP.NET MVC가 언떤 컨트롤러 클래스를 생성하고 어떤 메서드를 호출할 것인지 선택하는 방법을 완벽하게 제어할 수 있으며 서로 다른 방법으로 URL/쿼리문자열 형태로 전달되는 변수들을 자동적으로 파싱아혀 메서드의 매개변수로 대입하도록 할 수 있다. 이를 통해 사이트가 SEO(Search Engine Optimization:검색 엔진 최적화)에 완벽하게 최적화될 수 있으며 우리가 원하는 형태의 URL도 제공할 수 있게 된다.
MVC는 기본적으로 미리 정의된 URL 라우팅 규칙이 이미 등록되어 있으므로 우리는 이를 구축하지 않고 쉽게 애플리케이션을 제작할 수 있다. 라우팅 규칙은 프로젝트의 "Application" 클래스에서 찾을 수 있다. 프로젝트의 루트에 위치한 "Global.asax.cs"를 확인하여 봅니다.
위의 코드에서 호출하는 "routes.MapRoute()" 메서드는 "controller/action/{id}" 형식을 이용하여 요청된 URL을 클래스와 매핑하는 기본 URL 라우팅 규칙을 등록하였습니다.
기본적으로 등록 된 "controller/action/{id}" 형식의 URL 라우팅 규칙에 의하여 매핑될 수 있는 다양한 URL은 다음과 같습니다.
URL | 컨트롤러 클래스 | 액션 메서드 | 매개 변수 |
/Dinners/Deafults/2 | DinnersController | Details(id) | id = 2 |
/Dinners/Edit/3 | DinnersController | Edit() | id = 3 |
/dinners/Create | DinnersController | Create() | 매개 변수 없음 |
/Dinners | DinnersController | Index() | 매개 변수 없음 |
/Home | HomeController | Index() | 매개 변수 없음 |
/ | HomeController | Index() | 매개 변수 없음 |
컨트롤러를 지정하지 않으면, 디폴트로 정의되어 있는 /Home/Index/(id)가 선택되어지며, 액션 메서드의 이름을 지정하지 않으면 "Index"를 호출하게 된다. 또한 id변수를 지정하지 않으면 빈문자열이 지정된 것을 뜻한다. 이러한 규칙이 마음에 들지 않는다면, "RegisterRoutes 메서드를 수정하여 쉽게 라우팅 규칙을 변경할 수 있습니다.
3. DinnersController 클래스에서 DinnerRepository 클래스 활용하기
실제 동작을 구현하기 위하여 앞서 구현했던 DinnerRepository 클래스를 활용할 것입니다. "using" 구문을 이용하여 "NurdDinner.Models" 네임스페이스에 대한 참조를 추가한 후 DinnersController 클레스에 DinnerRepository 클레스의 인스턴스를 선언합니다.
namespace NerdDinner.Controllers //public ActionResult Index() // GET; /Dinners/Details/2 } |
여기까지 구현했으면 클라이언트에 응답으로 전달할 HTML 코드를 생성할 준비를 마친 셈입니다.
4. 뷰 활용하기
Controller의 Action Method에서 Response.Write() 메서드를 사용하여 HTML를 렌더링 할 수도 있지만, DinnersController 클래스의 액션메서드에서는 애플리케이션 로직과 데이터 로직만을 수행하고 별도의 View 템플릿에 전달하여 뷰로 하여금 출력을 담당하도록 하는것입니다.
컨트롤러의 로직과 뷰의 로직을 분리함으로써 얻을 수 있는 장점은 애플리케이션 로직과 UI렌더링 로직의 관계를 명확히 분리하여 독립적으로 동작하게 할 수 있습니다. 이렇게 함으로써 애플리케이션의 단위테스트를 UI 렌더링 로직과 무관하게 수행할 수 있습니다. 또한 애플리케이션을 수정하지 않고도 UI 렌더링 로직을 수정하는 것도 가능합니다.
DinnersController를 다음과 같이 수정합니다.
using System; namespace NerdDinner.Controllers //public ActionResult Index() // GET; /Dinners/Details/2 if (dinner == null) } |
"void"에서 "ActionResult"로 메서드의 시그니처(Singature)를 변경하고 Controller 기반 클래스가 제공하는 View() 메서드를 호출하여 "ViewResult" 개체를 리턴할 수 있습니다.
위의 코드에서 사용한 View(0 메서드의 시그니처는 다음과 같습니다.
viewResult View(string wiewName, object model);
View(0 메서드의 첫 번째 매개변수는 우리가 HTML 응답을 렌더링하기 위해 사용할 뷰 템플릿의 이름이며, 두 번째 매개변수는 뷰 템플릿이 HYML 응답을 렌더링하기 위해 필요로 하는 데이터를 가진 모델 개체입니다.
Details 액션 메서드는 URL에 지정된 ID값을 이용하여 Dinner 개체를 조회합니다. 조회한 Dinner 개체가
유효한 상태라면 View() 메서드를 호출하여 "Details" 뷰 템플릿이 조회된 Dinner 개체를 렌더링하도록 합니다. 만일, 조회된 개체가 유효하지 않은 상태라면 "NotFound" 뷰 템프릿을 출력함으로써 원하는 Dinner 개체를 얻어오지 못했음을 알리는 에러 메시지를 출력합니다.
5. NotFound 뷰 템플릿 구현하기
NotFound 액션 메서드 내에서 마우스 우클릭을 하여 이름을 "NotFound"로 명명합니다. 실행을 하고 브라우저의 주소 표시줄에 /dinnerss/defaults/777과 같이 입력하면 현재 데이터베이스에 존재하지 않는 데이터를 조회하려고 시도했기 때문에 DinnersController.Details() 메서드는 다음과 같이 "NotFound" 뷰 템플릿을 렌더링할 것입니다.
위의 그림을 통해서 우리는 우리가 방금 렌더링한 HTML이 전체 페이지의 일부로 삽입되어져 있는 것을 확인할 수 있습니다. 즉, 마스터페이지를 사용한 것입니다. 마스터 페이지에 관한 사항은 차후에 자세한 진행을 할 것입니다.
6. Details 뷰 템플릿 구현하기
다음과 같이 "Details" 메서드의 안쪽에 마우스을 위치시키고 우클릭을 하여 생성한다.
View 이름은 디폴드로 그래로 사용하고, MVC 3에서 추가된 "Razor" View engin를 사용한다.
Create a strongly-typed view에서 Model class에서 MVC 3에서 추가된 형식으로 scaffolder를 선택한다.
Scaffold Template에서 "Details"를 선택하고 "Use Layout or Master"체크해 준다. 이때 로케이션을 지정하지 않으면 아래와 같이 디폴트로 지정이 된다.
아래는 생성된 "Details.csHTML"입니다. 보는 바와 같이 <fieldset></fieldset>가 자동으로 마크업되어 있습니다. 이는 site.css에 정의된 레이아웃을 자동으로 불러와 배치한 것입니다.
@model NerdDinner.Models.Dinner @{ <h2>Details</h2> <fieldset> <div class="display-label">Title</div> <div class="display-label">EventDate</div> <div class="display-label">Description</div> <div class="display-label">HostedBy</div> <div class="display-label">ContactPhone</div> <div class="display-label">Address</div> <div class="display-label">Country</div> <div class="display-label">Latitude</div> <div class="display-label">Longitude</div> <div class="display-label">HostedById</div> |
실행을 하고 인터넷 주소창에 /dinners/details/1를 넣으면 아래와 같이 상세내역이 출력됩니다.
위의 그림은 디폴트로 생성된 화면이며, 편의성을 위해서 다양하게 편집할 수 있습니다. 아래는 fieldset를 지우고 간단하게 데인터베이스의 컬럼명을 한글로 바꾸어주고 불필요한 내용을 삭제하였습니다.
@model NerdDinner.Models.Dinner @{ <h2>만찬 상세 내역</h2> <h2><p> @Html.DisplayFor(model => model.Title)</p></h2> <p>시간 : @Html.DisplayFor(model => model.EventDate) </p> <p> |
아래는 상세 보기가 바뀐것을 보여줍니다.
|