좀 뒷북치는 감이 없진 않지만... 쿨럭 -ㅅ-;;
이 강좌는 2008년 6월부터 2008년 9월까지 월간 마이크로소프트웨어에 기고했던
ASP.NET MVC 연재의 원고를 그대로 옮긴 것입니다.
그렇기에 평소의 제 문체와 달리 경어를 사용하고 있지 않음을 양해해 주시기 바랍니다.
ASP.NET MVC와 춤을 - ASP.NET MVC 프레임워크 둘러보기
애플리케이션의 디자인 패턴에 대해 공부해 본 적이 있는 독자라면 MVC (Model-View-Controller) 패턴에 대해서는 익히 잘 알고 있을 것이다. MVC 패턴은 이미 자바 진영에서는 오래 전부터 활용되어 왔으며 MVC 패턴을 토대로 웹 애플리케이션을 구현하면 여러 이점을 얻을 수 있기 때문에 많은 개발자들이 스스로 ASP.NET 웹 애플리케이션에 MVC 패턴을 적용해 왔다. 그러나 이제는 ASP.NET MVC 프레임워크의 등장으로 더욱 손쉽고 편리하게, 게다가 프레임워크 수준에서 제공되는 MVC 패턴을 웹 애플리케이션에 적용할 수 있게 되었다. 이번 호에서는 ASP.NET MVC 프레임워크에 대해 개략적으로 살펴보는 시간을 가져보자.
연재 순서
ASP.NET MVC 프레임워크 둘러보기
ASP.NET MVC의 URL 라우팅 엔진, 그리고 모델 구성하기
ASP.NET MVC의 뷰와 컨트롤러 구성하기
ASP.NET MVC에 대한 못다한 이야기들
.NET 프레임워크 3.5가 정식으로 출시되고 ASP.NET 부분에서 크게 달라진 점이 없다는 사실에 많은 ASP.NET 개발자들이 실망감을 느끼고 있던 2007년 말, 마이크로소프트의 ASP.NET 팀은 ASP.NET 3.5 Extensions를 통해 ASP.NET MVC 프레임워크를 공개했다. ASP.NET MVC 프레임워크는 발표와 동시에 많은 개발자들에게 환영과 격려의 피드백을 받고 있다. 대체 어떤 물건이기에 많은 개발자들이 이렇게 큰 관심과 성원(?)을 보내는 것일까? 정말이지 궁금하지 않을 수 없다.
웹 폼 vs. MVC
우선 이 글의 주제인 MVC 패턴에 대해 잠시 살펴보기로 하자. MVC 패턴은 애플리케이션의 구조를 정의하기 위한 패턴이다. 크게 모델, 뷰 그리고 컨트롤러 등 세 가지 형태의 컴포넌트를 통해 애플리케이션을 구성하는 MVC 패턴의 장점은 각각의 컴포넌트의 역할이 명확하고 그 덕분에 각 컴포넌트가 완전히 독립적으로 동작할 수 있다는 점이다. 특히 이렇게 분리된 컴포넌트들은 애플리케이션을 테스트하기 위한 TDD (Test Driven Development) 개념을 적용하기에도 적합하다. MVC 패턴이 정의하는 각 컴포넌트의 역할은 다음과 같다.
Model: 모델은 애플리케이션이 수행해야 하는 비즈니스 로직을 담당하는 매우 중요한 컴포넌트이다. 대부분의 경우 모델링 과정을 통해 생성된 엔티티 클래스들이 모델 컴포넌트로서의 역할을 담당하게 되며 소규모 프로젝트라면 간단히 DataSet 클래스를 활용하는 수준이 될 수도 있지만 대형 프로젝트인 경우에는 Data Access Layer를 구성하는 어셈블리와 상호작용하는 Business Logic Layer를 모델 컴포넌트로 규정할 수 있다.
View: 뷰는 모델을 통해 수행된 비즈니스 로직의 결과를 보여주기 위한 역할을 담당하며 애플리케이션의 UI를 구성하는 컴포넌트이다. 이 컴포넌트는 어떠한 로직도 수행하지 않으며 모델로부터 전달된 데이터를 이용하여 화면을 구성한다.
Controller: 앞서 설명한 모델과 뷰의 중간에서 이들을 제어하기 위한 컴포넌트가 컨트롤러이다. 컨트롤러의 역할은 다른 컴포넌트와 사용자 사이의 상호작용을 담당하며 모델이 로직을 수행하는데 필요한 데이터를 수집, 전달하고 어떤 뷰를 통해 데이터를 보여줄 것인지를 결정하는 것이다.
이 MVC 패턴은 웹 프리젠테이션 패턴 중 하나로 분류된다. 즉, 데이터를 웹 페이지에 효과적으로 표현하고자 할 때 이용할 수 있는 패턴이라는 뜻이다. 그런데 사실 ASP.NET에는 이미 MVC 패턴이 녹아 들어있었다. 간단히 설명하자면 *.aspx 웹 폼 페이지가 뷰의 역할을 수행하며 *.aspx.cs 파일에 구현하는 코드 비하인드 클래스가 컨트롤러의 역할을 수행하는 것이다. 따라서 모델 역할을 담당할 클래스만 추가한다면 이 역시 MVC 패턴이라고 볼 수 있는 것이다.
앞서 소개한 MVC 패턴과는 약간 다르다고 생각될 수도 있겠지만 이는 ASP.NET의 MVC 패턴이 컨트롤러의 구현에 Page Controller 패턴을 이용하고 있기 때문이다. 반면 ASP.NET MVC는 Front Controller 패턴을 이용하여 구현되어 있다. 결국 이 둘 사이의 차이점은 Page Controller 패턴과 Front Controller 패턴이라는 상이한 구조를 채택하고 있는 것에서 비롯될 수 있다.
웹 폼의 Page Controller 패턴
Page Controller 패턴은 MVC 패턴을 적용하여 애플리케이션을 개발할 때 컨트롤러에 해당하는 컴포넌트를 구현하기 위한 패턴이다. Page Controller의 특징은 HTTP 요청을 처리하는 컨트롤러가 페이지마다 개별적으로 존재한다는 점이며 따라서 현재의 ASP.NET 웹 폼 모델은 코드 비하인드 클래스가 컨트롤러의 역할을 담당하고 있는 MVC 패턴이 적용되어 있다고 볼 수 있다.
앞서 설명했듯이 Page Controller 패턴의 특성 상 컨트롤러를 특정 페이지와 관련된 영역만을 커버하면 되기 때문에 상대적으로 간단하게 구현할 수 있다. 뿐만 아니라 컨트롤러의 기반 클래스를 구현함으로써 코드를 재사용 하기에도 매우 편리하다. 반면 클래스의 상속 계층이 깊어지면 그에 따른 부담이 생길 뿐 아니라 컨트롤러와 뷰가 너무 타이트하게 연결되는 경향이 있다. 또한 컨트롤러 자체가 기반 프레임워크에 대한 의존도가 높다는 점도 단점으로 작용한다. 아래 그림은 Page Controller 패턴의 구조를 보여준다.

그림 1. Page Controller 패턴
ASP.NET MVC 프레임워크의 Front Controller 패턴
MVC 패턴에서 컨트롤러를 구현하기 위한 또 다른 패턴으로는 Front Controller 패턴이 존재한다. 이 패턴은 요청을 처리하는 단일 컨트롤러를 사용한다는 점에서 앞서 살펴본 Page Controller 패턴과 다르다. Front Controller 패턴에서 컨트롤러는 인바운드 HTTP 요청에 따라 해당 요청을 처리하기 위한 적절한 커맨드 컴포넌트를 생성하는 일종의 핸들러와 핸들러에 의해 요청을 처리하도록 선택되는 커맨드 컴포넌트 등 두 가지 컴포넌트로 구성된다.
Front Controller 패턴을 적용하게 되면 Page Controller 패턴과 달리 비즈니스 로직을 중앙으로 집중 시킬 수 있는 장점이 있다. 또한 Page Controller 패턴과 비교해 볼 때 각 컴포넌트들의 독립성이 상대적으로 향상되기 때문에 애플리케이션이 유연해지며 컴포넌트 별로 테스트를 진행하기에도 편리해진다. 뿐만 아니라 비록 물리적으로는 여러 개의 클래스로 분리되어 구현될 수 있기는 하지만 논리적으로 컨트롤러는 하나만 존재하는 셈이므로 그만큼 웹 서버의 구성이 간단해 질 수 있다는 것도 장점이다.
반면 모든 요청에 대한 처리를 하나의 컨트롤러에 의존하기 때문에 성능 상의 문제가 발생할 수 있으며 다양한 명령을 처리하기 위해 컨트롤러가 더욱 복잡해 진다는 문제를 안고 있다. 아래 그림은 Front Controller 패턴의 구조를 보여준다.

그림 2. Front Controller 패턴
지금까지 ASP.NET 웹 폼 모델과 ASP.NET MVC 프레임워크가 구현하고 있는 서로 다른 형태의 MVC 패턴에 대해 살펴보았다. 이들 패턴에 대한 더 자세한 내용은 패턴 관련 전문 서적이나 마이크로소프트의 Patterns and Practices와 같은 웹사이트를 참고하기 바란다. 필자가 이들 패턴에 대해 간략히 소개한 이유는 이 글이 ASP.NET 웹 폼 모델의 단점을 들춰내고 ASP.NET MVC 프레임워크를 칭송하기 위한 혹은 그 반대의 목적을 위한 것이 아니기 때문이다.
결론부터 말하자면 개발자는 주어진 문제를 해결하는데 적합한 방법을 선택해야 하며 지금까지 설명한 내용의 목적은 ASP.NET 웹 폼 모델과 ASP.NET MVC 프레임워크의 특징과 장단점을 파악함으로써 개발자가 올바른 선택을 할 수 있도록 돕기 위함이다. 중요한 것은 ASP.NET MVC는 ASP.NET이 발전된 모델이 아니라 단지 개발자가 선택할 수 있는 또 다른 개발 모델이라는 점을 인식하는 것이다.
ASP.NET MVC 프레임워크의 특징
ASP.NET MVC는 기존의 웹 폼 모델과는 전혀 다른 개발 방법을 제공한다. ASP.NET MVC를 토대로 애플리케이션을 개발하려면 이미 많은 개발자들에게 익숙한 웹 폼 모델은 아예 잊어버리는 편이 나을 정도이다. 어떤 면에서 차이가 있는지 살펴보도록 하자.
요청 모델: 기존의 ASP.NET 웹 폼 모델에서는 각각의 HTTP 요청은 웹 폼 페이지와 일대일로 매칭되어 있었으며 URL 자체가 서버에 위치한 페이지 리소스의 경로를 의미하는 것이었다. 그러나 ASP.NET MVC에서는 REST 방식과 유사한 형식의 URL을 사용한다. 이제 URL은 페이지를 가리키는 것이 아니라 애플리케이션에 특정 동작을 요구하는 요청으로서의 역할을 하게 된다.
사라진 포스트 백: 더욱 당황스러운 점은 이제 더 이상 포스트 백 개념이 존재하지 않는다는 것이다. 포스트 백 개념이 사라졌다는 것은 서버 폼과 ViewState 그리고 다양한 서버 컨트롤 등 ASP.NET이 그 동안 장점으로 내세웠던 많은 것들을 더 이상 활용할 수 없다는 것을 의미한다.
페이지의 역할: 웹 폼 모델에서는 페이지가 뷰(*.aspx 파일)와 컨트롤러(*.aspx.cs)의 역할을 담당했었다. 그러나 ASP.NET MVC에서 페이지는 뷰를 위한 템플릿으로서의 역할을 수행한다. 나중에 자세히 설명하겠지만 ASP.NET MVC 프로젝트를 생성하면 *.aspx 페이지에 대한 요청을 처리하는 핸들러가 페이지 핸들러에서 System.Web.HttpNotFoundHandler 핸들러로 변경되었다. 이는 *.aspx 페이지에 대한 요청을 보내면 HTTP 404 오류를 만나게 된다는 뜻이다.
이상의 내용으로 미루어 볼 때 웹 폼 모델과는 많은 부분에서 차이가 있음을 알 수 있다. 조금 더 자세한 내용들은 앞으로의 이야기를 통해 계속해서 살펴보기로 하고 지금부터는 Visual Studio 2008을 이용하여 실제로 ASP.NET MVC 프레임워크 프로젝트를 만들어 보자.
Hello, ASP.NET MVC
이 글을 작성하는 현재 ASP.NET MVC 프레임워크는 Preview 버전 2가 출시된 상태이다. ASP.NET MVC Preview 2는 다음 경로를 통해 다운로드 할 수 있다.
http://go.microsoft.com/fwlink/?LinkID=110956
늘 그랬듯 ASP.NET MVC의 설치 역시 몇 번의 클릭으로 끝낼 수 있다. 다만 한글 Visual Studio 2008 사용자라면 약간의 추가 작업을 실행해 주어야 한다. 우선 ASP.NET MVC Preview 2를 설치를 완료한 후 Visual Studio 2008이 설치된 C:\Program Files\Microsoft Visual Studio 9.0 폴더에서 필요한 작업들을 수행해야 한다. 다음 단계를 차례대로 실행해 보자. 지금부터 언급하는 폴더는 모두 Visual Studio 2008 설치 폴더를 기준으로 한 것이다.
1. Common7\IDE\ProjectTemplates\CSharp\Web 폴더의 하위 폴더인 1033 폴더에 MvcWebApplicationProjectTemplateP2.cs.zip 파일을 존재한다. 이 파일을 1033이 아닌 1042 폴더로 복사 혹은 이동한다. 물론 이 파일은 CSharp 폴더가 아닌 VisualBasic 폴더에도 존재하므로 VB.NET 개발자는 CSharp 폴더 대신 VisualBasic 폴더의 파일을 이용해야 한다.
2. Common7\IDE\ItemTemplates\CSharp\Web\MVC\1033 폴더에는 ASP.NET MVC 프로젝트를 위한 아이템 템플릿 파일들이 존재하고 있다. 이 파일들 역시 1042폴더로 이동하거나 복사해야 한다. 마찬가지로 CSharp 폴더 대신 VisualBasic 폴더에도 이 파일들이 존재하고 있다.
3. 이제 시작 메뉴에서 [Microsoft Visual Studio 2008 > Visual Studio Tools > Visual Studio 2008 명령 프롬프트] 항목을 클릭하여 커맨드 창을 연다. Windows Vista 사용자라면 관리자 권한으로 실행해야 한다. 그리고 다음의 명령을 수행한다.
devenv /installvstemplates
명령의 실행이 완료되면 이제 한글 Visual Studio 2008에서도 ASP.NET MVC Preview 2를 사용할 수 있게 된 것이다.
ASP.NET MVC 프레임워크의 설치를 마쳤다면 이제 예제 프로젝트를 생성해보자. Visual Studio 2008을 실행하고 새 프로젝트 대화 상자를 연 후 [ASP.NET MVC Web Application] 템플릿을 선택하고 [확인] 버튼을 클릭한다.
새로운 프로젝트를 생성하면 ASP.NET MVC는 기존의 웹 애플리케이션 프로젝트와는 사뭇 다른 프로젝트의 골격을 만들어 준다. ASP.NET MVC가 기본적으로 생성하는 프로젝트의 구조는 아래 화면 1과 같다.

화면 1. ASP.NET MVC 웹 애플리케이션 프로젝트의 구성
화면 1에서 보듯이 프로젝트의 구성은 매우 단순하면서도 직관적이다. 프로젝트 내에서 모델과 뷰, 그리고 컨트롤러들은 각각 Models, Views, Controllers 폴더에 만들어진다. 특히 Views 폴더에는 Shared라는 이름의 폴더가 존재하는데 이 폴더는 마스터 페이지나 User Control 등 여러 뷰가 공유하는 공통의 뷰를 구현하는 파일들을 추가하기 위한 폴더이다.
마지막으로 Contents 폴더는 CSS 파일이나 JS 파일 혹은 HTML 파일 등 정적 컨텐츠를 가지는 파일들을 위한 폴더이다. 이 기본 프로젝트를 실행하면 아래 그림과 같이 ASP.NET MVC에 대해 간략히 소개하는 예제 애플리케이션을 볼 수 있다.

화면 2: 예제 ASP.NET MVC 애플리케이션을 실행한 모습
화면 2에서 보듯이 이 예제 애플리케이션은 Home과 About 두 개의 탭을 제공한다. About 탭을 클릭해보면 URL이 아래와 같이 표시되는 것을 확인할 수 있다.
http://localhost:56336/Home/About
앞서 설명했듯이 각 뷰에 대한 요청 URL은 더 이상 ~/About.aspx와 같은 형태가 아니다. 이와 같은 형태의 URL이 제공될 수 있는 이유는 ASP.NET MVC 프레임워크에 강력한 URL 라우팅 기능이 포함되어 있기 때문이다. 솔루션 탐색기에서 Global.asax.cs 파일을 열어보면 기본적인 URL 라우팅 설정이 구현되어 있는 것을 확인할 수 있다.
코드 1: Global.asax.cs 파일의 URL 라우팅 설정
public static void RegisterRoutes(RouteCollection routes) {
routes.Add(new Route("{controller}/{action}/{id}", new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(new { action = "Index", id = "" }),
});
routes.Add(new Route("Default.aspx", new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
});
}
protected void Application_Start(object sender, EventArgs e) {
RegisterRoutes(RouteTable.Routes);
}
코드에서 보듯이 URL 라우팅은 웹 애플리케이션이 시작할 때 RegisterRoutes 메서드 호출을 통해 설정된다. 따라서 RegisterRoutes 메서드에 각자 필요한 URL 라우팅 설정을 추가하면 된다. 예제 애플리케이션에는 두 가지 설정을 추가하고 있다.
URL 라우팅에 대한 자세한 내용은 다음 호에 살펴보겠지만 우선 이 코드를 간략히 설명하자면 첫 번째 라우팅 설정은 해당 도메인 (예제에서는 localhost가 될 것이다.)에 대한 요청을 받은 경우에는 Index라는 액션을 수행하도록 설정한 것이며 두 번째 라우팅 설정은 Default.aspx 페이지에 대한 요청을 받으면 역시 Home 컨트롤러의 Index 액션을 취하도록 설정한 것이다.
초 간단 MVC 페이지 구현하기
이제 이쯤 되면 예제를 하나쯤 다룰 때가 되었고 사실 그 예제가 무엇인지도 대충 짐작할 것이다. 개발자를 위한 단골 메뉴 Hello, World 예제 페이지를 MVC 패턴에 맞추어 추가해 보자. 앞서 Global.asax.cs 파일에서 Default.aspx 파일에 대한 기본 컨트롤러의 이름이 Home으로, 액션의 이름은 Index로 지정되었던 것을 기억할 것이다.
따라서 웹 서버는 Default.aspx 페이지에 대한 요청을 받으면 HomeController 컨트롤러 클래스의 Index 메서드를 호출하게 된다. 따라서 우리가 새로운 페이지를 처리하려면 우선 컨트롤러 클래스에 액션 메서드를 작성해야 한다.
솔루션 탐색기에서 Controllers\HomeController.cs 파일을 열고 아래와 같이 Hello라는 이름의 메서드를 추가해보자.
코드 2: HomeController 컨트롤러의 Hello 액션 메서드
public void Hello() {
RenderView("Hello");
}
ASP.NET MVC가 ASP.NET 3.5 Extensions Preview에 포함되어 발표되었을 때는 액션 메서드에 대해서는 [ControllerAction]이라는 특성 클래스를 지정해 주었어야 했다. 그러나 컨트롤러 클래스의 대부분의 메서드가 액션 메서드인 관계로 ASP.NET MVC Preview 2에서는 컨트롤러 클래스의 public 메서드는 모두 묵시적으로 액션 메서드로 취급하는 대신 액션 메서드로 취급하지 않을 메서드에 대해서는 NonAction 특성을 지정하는 방식으로 변경되었다.
Controller 클래스는 RenderView라는 메서드를 제공하는데 이 메서드는 컨트롤러가 요청에 대한 처리를 완료한 후 그 결과를 렌더링할 뷰를 선택하도록 하는 메서드이다. 이 메서드는 다음과 같은 형식들이 제공된다.
RenderView(string viewName);
RenderView(string viewName, object viewData);
RenderView(string viewName, string masterName);
RenderView(string viewName, string masterName, object viewData);
보다시피 총 4가지 버전의 재정의된 RenderView 메서드들이 제공된다. 우선 viewName 매개 변수는 렌더링 할 뷰의 이름이며 viewData 매개 변수는 지정된 뷰를 렌더링할 때 뷰로 전달될 데이터를 지정할 수 있는 매개 변수이다. 마지막으로 masterName 매개 변수는 해당 뷰를 렌더링할 때 해당 뷰가 사용할 마스터 페이지의 이름이다. 코드 2에서 우리가 작성한 Hello 액션 메서드에서는 이 4가지 RenderView 메서드 중 첫 번째 재정의 버전을 사용하고 있으며 Hello라는 문자열을 전달하여 HomeController 클래스가 Hello라는 이름의 뷰를 선택하도록 하였다.
이제 뷰를 추가해보자. ASP.NET MVC에서 뷰는 *.aspx 페이지를 템플릿으로 활용한다. 따라서 Hello.aspx 라는 이름의 웹 폼 페이지를 뷰 템플릿으로 추가해 주어야 한다. 이 파일을 추가해야 하는 위치는 Views\Home\ 폴더이다. 솔루션 탐색기에서 Views\Home 폴더를 마우스 오른쪽 버튼으로 클릭하고 [추가 > 새 항목] 메뉴를 차례로 클릭하면 [새 항목 추가] 대화 상자가 나타난다.
이 예제 애플리케이션은 마스터 페이지를 사용하고 있으므로 아래 화면 3과 같이 [새 항목 추가] 대화 상자의 왼쪽 범주 패널에서 [웹 > MVC] 노드를 선택하고 오른쪽의 템플릿 패널에서 [MVC View Content Page] 항목을 선택하고 이름을 [Hello.aspx]라고 지정하자.

화면 3: ASP.NET MVC 프로젝트 용 아이템 템플릿들
예제의 단순함을 위해 새로 추가된 뷰는 간단한 문자열만 출력하도록 구현해 보자. 기본적으로 추가된 <asp:Content> 컨트롤 내에 다음과 같이 코드를 작성해 보자.
<asp:Content ID="Content1"
ContentPlaceHolderID="MainContentPlaceHolder"
runat="server">
<h2>Hello, ASP.NET MVC!</h2>
</asp:Content>
다음으로 해야 할 일은 새로 추가한 뷰를 요청할 수 있는 메뉴를 예제 애플리케이션에 추가하는 일이다. Views\Shared\Site.Master 페이지를 열고 22번 라인 이후에 다음의 코드를 추가해보자.
코드 3: 새로운 액션에 대한 링크를 생성하는 코드
<li>
<%= Html.ActionLink("Hello", "Hello") %>
</li>
위의 코드에서 사용한 Html 객체는 ASP.NET MVC 프레임워크가 제공하는 HtmlHelper 클래스를 사용하는 속성이며 ASP.NET MVC 마스터 페이지나 뷰 페이지의 부모 클래스인 ViewMasterPage 클래스나 ViewPage 클래스에 정의되어 있다. 이 HtmlHelper 클래스의 ActionLink 메서드는 주어진 액션에 대한 URL을 생성해 주는 역할을 담당하며 메서드의 첫 번째 매개 변수는 링크의 텍스트이고 두 번째 매개 변수는 지정된 액션에 대한 링크 텍스트이다. 따라서 위의 코드는 다음과 같은 코드를 만들어 낸다.
<a href=”/Home/Hello”>Hello</a>
이제 예제 프로젝트를 실행해 보면 화면 4와 같이 하나의 탭이 더 추가된 것을 확인할 수 있으며 새로 만들어 진 Hello 탭을 클릭해보면 조금 전에 추가했던 Hello.aspx 뷰가 나타나는 것을 확인할 수 있을 것이다.

화면 4: 새로운 탭이 추가된 모습

화면 5: 새로운 뷰가 표시된 모습
ASP.NET MVC 프레임워크가 새롭게 제공하는 클래스들
코드나 개념 상의 차이점을 제외하고는 예제 애플리케이션을 구현하는 과정은 이전과 크게 다르지 않아 보이겠지만 사실 보이지 않는 부분에서 많은 차이점이 있다. 가장 대표적인 차이점은 앞서 예제에서 사용하고 있는 마스터 페이지나 웹 페이지는 모두 새로운 타입들을 사용하고 있다는 점이다. ASP.NET MVC 프레임워크에서 새롭게 제공하는 클래스들의 목록은 아래 표 1을 참고하기 바란다.
표 1: ASP.NET MVC 프레임워크에 새롭게 추가된 클래스들
지금까지 예제를 통해 컨트롤러에 액션을 정의하고 해당 액션을 호출하는 방법과 액션의 실행 결과를 뷰를 통해 렌더링 하는 방법까지 살펴보았다. 물론 이로써 ASP.NET MVC의 모든 부분을 살펴본 것은 아니지만 대략적으로나 ASP.NET MVC 웹 애플리케이션을 어떻게 구현해 나가는지에 대해 이해하기에는 무리가 없었을 것이다.
다만 ASP.NET MVC를 처음 대하면서 가장 당황스러운 것은 서버 폼의 사용을 권장하지 않는다는 점이다. 서버 폼이 없다면 데이터 바인딩은 어디서 어떻게 해야 하는지 혹은 그 동안 서버 컨트롤로 수행해 오던 많은 작업들은 이제 어떤 방법으로 수행해야 하는지가 당장 문제가 된다.
사실 이와 같은 코드는 생산성은 뛰어날지 모르지만 유지보수 측면에서는 결코 좋은 방법은 아니었으며 ASP.NET에서 서버 컨트롤 개념이 추가된 이유도 바로 이런 스파게티 코드를 없애보자는 의미였다.
어찌됐든 뷰 페이지도 자신이 표시할 데이터를 가공하기 위한 일련의 로직이 필요할 것이며 필자는 개인적으로 이런 코드라도 코드 4와 같은 방법으로 작성되는 것을 그다지 좋아하지 않는다. 다행스러운 것은 ASP.NET MVC 프로젝트에서 뷰 템플릿 역할을 수행하는 페이지도 기존의 페이지 라이프 사이클을 모두 실행한다는 점이다.
즉, Page 클래스의 PreInit, Init, InitComplete, PreLoad, Load, LoadComplete, PreRender, PreRenderComplete, Unload 등 페이지 라이프 사이클과 관련된 모든 이벤트는 여전히 실행된다. 그도 그럴 것이 이미 ASP.NET은 페이지를 구성하고 컴파일하고 그 결과를 렌더링하는데 필요한 코드와 아키텍처를 이미 가지고 있었으며 ASP.NET MVC 프레임워크에서 이런 부분을 다시 재정의할 필요는 없었을 것이다. 사실 이런 부분을 다시 재정의한다는 것은 새로운 웹 애플리케이션 프레임워크를 만드는 것과 다를 바 없기 때문이다.
또 한 가지 중요한 것은 비록 서버 폼이 없다 하더라도 서버 폼을 필요로 하지 않는 서버 컨트롤들은 얼마든지 활용할 수 있다는 점이다. 서버 폼이 필요치 않은 서버 컨트롤에는 System.Web.UI.HtmlControls 네임 스페이스에 구현된 HTML 서버 컨트롤은 모두 포함될 뿐 아니라 Repeater와 같은 일부 데이터 바운드 컨트롤도 포함된다.
그러면 ASP.NET MVC 프로젝트에서 페이지의 라이프 사이클 이벤트들이 올바르게 실행되는지를 확인하기 위해 앞서 작성한 예제를 간단히 수정해 보자. 우선 HomeController 컨트롤러에 추가했던 Hello 액션 메서드를 아래와 같이 수정해보자.
이 코드는 데이터 모델로부터 DataTable 객체를 통해 데이터를 전달받은 상황을 재연하기 위해 작성된 코드이며 DataTable 객체에 두 개의 컬럼을 추가하고 임의의 값을 채워 넣었다. 그리고 이 DataTable 객체를 뷰에 전달하기 위해 RenderView 메서드의 두 번째 인수로 전달하였다. 다음으로 Hello.aspx 페이지를 열고 아래와 같이 Repeater 컨트롤을 추가해 보자.
코드에서 보다시피 이미 익숙한 데이터 바인딩 식과 Repeater 컨트롤을 이용하여 데이터를 바인딩하는 코드를 작성하였다. 이제 Hello.aspx.cs 파일을 열고 다음과 같이 코드를 작성해 보자.
코드 7. Hello.aspx.cs 파일의 비하인드 코드
public partial class Hello : ViewPage<DataTable> {
protected override void [안내]태그제한으로등록되지않습니다-xxOnLoad(EventArgs e) {
base.[안내]태그제한으로등록되지않습니다-xxOnLoad(e);
이 코드에서 주목해야 할 점은 크게 두 가지이다. 첫 번째는 이 페이지의 [안내]태그제한으로등록되지않습니다-xxOnLoad 메서드가 오버라이딩 되었다는 점이다. 따라서 이 페이지가 올바르게 동작한다면 이는 페이지의 라이프 사이클 이벤트들이 여전히 실행되고 있음을 의미한다.
두 번째로는 Hello클래스의 선언부를 보면 이 클래스가 상속하는 타입은 ViewPage 타입이 아니라 이 클래스의 제네릭 버전인 ViewPage<DataTable> 타입이다. 앞서 컨트롤러에서 RenderView 메서드를 호출할 때 ViewData로 DataTable 객체를 전달하였으므로 이 페이지가 DataTable 객체를 올바르게 전달받아 사용하려면 이와 같이 ViewPage<T> 제네릭 타입을 사용해야 한다.
ViewPage 클래스는 컨트롤러로부터 전달된 데이터를 뷰 페이지에서 사용할 수 있도록 하기 위해 ViewData 속성을 제공한다. 우리는 ViewPage<DataTable> 타입의 클래스를 상속하고 있으므로 ViewData 속성은 DataTable 타입을 리턴하게 된다. 따라서 이 속성이 리턴하는 값을 Repeater 컨트롤의 DataSource 속성에 대입하면 지금까지 익숙하던 방식대로 데이터 바인딩을 수행할 수 있다.
이번 호에서는 MVC 패턴의 구조에 대해 알아보고 기존의 ASP.NET 웹 폼 모델과 ASP.NET MVC 프레임워크를 비교해보았다. 또한 ASP.NET MVC 프레임워크를 설치하고 간단한 예제를 작성해 봄으로써 ASP.NET MVC 프레임워크를 이해하기 위한 토대를 마련하는 것이 목적이었다. 다음 호에서는 ASP.NET MVC 프레임워크가 제공하는 URL 라우팅 엔진과 MVC 중 첫 번째 키워드로 등장하는 모델에 대해 알아보도록 하자.
첫댓글 감사감사해염~^^
너무 자세히 기재되어서 누구나 이해할 수 있게 기재되었네요..^__^
전 누구나 이해하는것 조차 이해를 못 하는 군요.
블로그같은데로 퍼가도 되는건가요? ㅋ
좋은 자료 감사합니다!! 이글 보고 MVC에 한발 더 다가섰어요.
감사합니다~ ^^
감사합니다
오래된 글에 아직도 답글을 주시는 분들이 계시다니 저도 감사합니다. :)
이런 글이 있었네요. 처음 asp.net 할때 쯤이네요.