아래 내용은 asp.net 의 MVC Tutorial 란에 있는 ASP.NET MVC OverView 를 정리한 내용입니다.
ASP.NET MVC 개요
ASP.NET MVC 프레임웍은 어플리케이션을 크게 모델(Model)-뷰(View)-컨트롤러(Contorller) 로 나누어 준다. 이 프레임웍은 ASP.NET 웹폼도 지원하며 이를 사용한 MVC 디자인 모델 기반의 웹 어플리케이션을 쉽고 빠르게 개발 할 수 있다.
ASP.NET MVC 프레임웍은
1. 가볍고
2. 마스터 페이지나 멤버쉽 기반의 인증 기능 등 기존의 ASP.NET 의 기능들이 통합되어 사용이 가능하다.
3. System.Web.Mvc 네임스페이스에 정의 되어 있으며
4. 기본적으로 System.Web 네임스페이스의 일부분으로 지원되고 있다.
MVC 는 많은 개발자들에게 친근한 표준 디자인 패턴이다. (난 MVC 디자인 패턴에 대해 듣기는 많이 들었지만 직접적인 경험이 없어 궁금할 뿐이다. .. 친근해야 하나? ㅡ,.ㅡ)
특정 유형의 웹 어플리케이션은 MVC 프레임웍을 사용함으로 큰 이익 창출은 물론,
전통적인 웹폼과 포스트백 기반의 ASP.NET 어플리케이션 패턴도 지속적으로 사용할 수도 있다.
하지만 두가지 패턴을 섞어 사용 할 수는 없다.
The MVC 프레임웍의 컴포넌트를 살펴보자:
Models. 모델 객체는 전체 어플리케이션 중 데이터 도메인에 비지니스 로직을 실행하는 부분으로 데이터베이스와 자주 소통 하여 조회 및 저장을 실행한다. 예를 들어 Product 객체는 데이터베이스에서 정보를 조회해 오기도 하고 업데이트 된 정보를 SQL 서버의 Product 테이블에 저장하기도 한다. dataset 을 읽어 뷰로 보내기만 하는 작은 어플리케이션에서는 모델을 물리적이라기 보다는 개념적으로 많이 본다. 왜냐하면 이런 어플리케이션에서는 물리적인 모델 레이어와 관련 클래스들이 존재하지 않기 때문이다. 이런 케이스에서는 Data set 이 모델 객체 역할을 한다고 보면 된다.
Views. 뷰 는 어플리케이션의 사용자 인터페이스(UI) 를 보여주는 컴포넌트 이다. 일반적으로 UI는 모델 데이터로 부터 만들어진다.
Controllers. 컨트롤러 컴포넌트는 사용자와 소통하여 모델과 함께 움직이며 뷰를 렌더링하여 UI 를 화면에 표시한다. MVC 어플리케이션에서는 뷰는 정보를 보여주고, 컨트롤러는 사용자의 입력값 혹은 요청에 응답 한다. 예를 들어, 컨트롤러는 쿼리 스트링 값들을 모델에 넘겨 주어 데이터베이스에 그 값들을 사용하여 쿼리의 결과값을 받아온다.
MVC 디자인 패턴은 어플리케이션을, 입력 로직, 비지니스 로직 그리고 UI 로직 등으로 나누어 서로 결속력이 느슨하게 만들어 준다. UI 로직은 뷰에, 입력 로직은 컨트롤러에 그리고 비지니스 로직은 모델에 속한다.
이렇게 나누게 되면 개발 시 하나에 집중 할 수 있도록 하여 개발의 복잡도와 작업의 의존도를 떨어뜨리는 효과를 가져온다.
예로 디자이너는 비지니스 로직에 의존하지 않고 뷰에만 집중할 수 있다.
추가적으로 MVC 패턴에서는 ASP.NET 웹 어플리케이션 기반에서 보다 훨씬 수월하게 테스트를 할 수 있다.
예를 들면 웹폼 기반의 ASP.NET 웹 어플리케이션은 하나의 클래스에서 사용자의 입력값을 받아 처리하고, 결과값을 보여준다. 자동으로 짜여지는 웹폼기반 ASP.NET 어플리케이션을 테스트 하기 위해선 테스트 하는 각각의 페이지들의 클래스 및 모든 자식 컨트롤들과 추가적으로 의존된 클래스틀 까지 모두 작동 시켜야 한다.
이러한 웹폼 기반의 ASP.NET 어플리케이션에서는 하나의 페이지에서 많은 클래스들이 함께 움직여 동작하기 때문에 하나의 기능에 집중된 테스트 (유닛테스트: Unit Test) 를 하기란 참 어렵다. 또한 웹서버도 필요로 한다.
MVC 어플리케이션에서의 테스트는 MVC 프레임웍이 하나의 유닛을 테스트 할 수 있도록 나머지 프레임웍에서 인터페이스 사용함에 있어 무겁게 하는 컴포넌트들을 분리시켜 준다. 이로써 보다 가볍게 부분적인 테스트(유닛테스트)를 가능하게 해준다.
모델 뷰 컨트롤러 컴포넌트들끼리의 느슨한 결속력은 한명의 개발자는 뷰의 작업을 하고, 또 다른 개발자는 컨트롤러 로직을 짜며 나머지 한명을 모델에서 비지니스 로직에만 개발 할 수 있게 하여 서로 의존적이지 않은 개발 즉 Parallel(수평) 개발을 가능케 한다.
(개인적인 생각: 음.. 선배들에게 듣기론 수평적인 개발 보다는 수직적인 개발이 더 개발에 수월하다고 하던뎀, 뭐가 좋은지는 난 잘 모르겠다. 개인적으로는 수직적인 개발이 조금 더 익숙하다고 할까? ㅡ,.ㅡa)
그럼 언제 MVC 디자인 패턴을 사용해야 하는가?
웹어플리케이션을 개발 할 때 ASP.NET MVC 프레임웍을 사용해야 하는지, 혹은 ASP.NET 웹폼 모델을 사용해야 하는지에 대한 고민을 하게 될 것이다.
MVC 프레임웍이 기존의 웹폼 모델을 대체 할 수는 없다. 즉 MVC 프레임웍만을 사용하려면 MVC 프레임웍을 사용하는 웹어플리케이션을 새로 개발하든지, 아니면 웹폼 기반의 어플리케이션이 있는데 추가적인 작업을 해야 한다면 웹폼 기반 디자인을 지속적으로 사용해야 할 것이다.
그렇기 때문에 MVC 프레임웍이 사용되어야 할지 혹은 웹폼 모델이 사용되어야 할지는 서로의 장단점을 잘 따져 결정해야 할 것이다.
MVC의 장점
1) 모델 뷰 컨트롤러로 어플리케이션을 나누기 쉽다.
2) MVC 프레임웍은 View State 이나 서버 기반의 폼을 사용하지 않아 개발자로 하여금 어플리케이션 이 행하는 모든 기능적 3) 프로세스에 대한 전체적인 제어권을 가질 수 있게 한다.
4) 웹어플리케이션의 요청을 하나의 컨트롤러를 통하여 처리하는 프론트 컨트롤러 패턴(Front Controller Pattern)을 사용하여 리치 라우팅 인프라스트럭처(Rich Routing Infrastructure) 를 지원하는 어플리케이션 디자인을 가능케 한다.
5) 더 나은 test-driven development (TDD) 을 제공한다.
6) 많은 개발자들과 웹 디자이너들이 구성된 팀이 지원하는 웹 어플리케이션에 적합하다.
웹폼 기반의 장점
1) HTTP 을 사용하여 상태 보전을 하는 이벤트 모델을 지원한다. 웹폼 기반 어플리케이션은 수백개의 서버 컨트롤에서 지원하는 많은 이벤트들을 제공한다.
2) Page Controller 패턴을 사용하여 각각의 페이지에 기능을 탑재시킨다.
3) 상태정보 관리가 쉬운 View State 나 서버 기반 폼들을 사용한다.
4) 작은 규모의 개발팀에서 많은 종류의 컴포넌트들을 가지고 빠른 속도로 어플리케이션을 개발할 때 적합니다.
5) 대체적으로 어플리케이션 개발의 복잡도가 낮다. 컴포넌트들(페이지 클래스, 컨트롤 등)이 강한 결속력으로 통합되어 있고, MVC 모델 보다 코드 줄 수가 적은 편이다.
알고 있는 내용이 아니라, 읽고 이해한 내용을 옮기다 보니 어색한 부분들도 있고, 미흡한 점들도 많네요.
오역이나 잘못된 부분이 있으면 지적 부탁드립니다.
이유인 즉슨.. 개발/테스트 서버의 노후화 및 말도 안돼는 프로그램들이 많이 설치 되어 있어서, 계속 느려지고 있었고, 프로그램에서 오류가 나고 있었기 때문에, 새로운 서버를 받게 되었다.
세팅이야 모.. 스무스~ 하게 될줄 알았지만.. 2년전에 해본 세팅.. 한번 더 해보려고 하니 기억이 가물가물.
asp 페이지들을 옮기고..
visual basic 으로 만들어진 dll 파일들을 옮겨 컴포넌트 서비스에 등록하면서 사용하는, 사용하지 않은 dll 들을 실서버와 비교하며 재등록을 해야 했다.
MYSQL 도 2000 에서 사용하고 있던 테스트 자료들을 2005 로 dettach, attach 하면서 옮긴 후, 계정 세팅을 해줘야 했다..
아웅...
근데 이게 뭐냐.. IIS 서비스 세팅 완료 한 뒤, 웹페이지로 들어가려고 하면 윈도우 보안 창이 뜨면서 암호를 넣으라고 한다.
헐..
ㅡ"ㅡ 당췌.. 왜..
IIS 세팅 시 디렉토리 보안 쪽에서 넣어 줬던 IUSR_컴퓨터이름 사용자의 암호가 컴퓨터 로그인 시 암호와 다르기 떄문에 팝업이 뜨는건뎀..세팅 시 제대로.. 넣어 줬는데,???? !!!!!! 어쩌면 그 두번이 동일한 배열로 틀리게.. 입력이 되었는지 나도 잘 모르겠지만..
헐.. 이녀석 문제로 꽤 시간 허비한걸 생각해 보면.. ㅋㅋㅋ 기억을 잘 하고 살아야 겠다.. :) 는 결론 뿐...
언젠가 잘 쓰던 컴퓨터에 우분투를 설치하기로 맘먹고 윈도우 2008 사용하던 컴퓨터에 파티션을 나누어 우분투 9.04 를 설치했다.
우분투를 설치한 까닭은? 그냥.. 이라기 보다는 루비 온 레일즈 공부하기 위해서다. 지금껏 이것저것 만들면서 우분투 UI 와도 꽤 친해지고 꼭 필요할 때만 윈도우 2008 로 부팅한 기억이 난다.
(가끔 일하기 위해서 윈도우를 사용해야 하고, 은행일이나 웹하드에서 파일 다운받을 때에는 그냥 윈도우로 부팅해서 사용했기 때문이다.)
뭐 여하튼 윈도우 7 이 나왔다고 해서 기웃거리다 보니 꽤 속도도 향상되고 뭐 그렇다고 해서 이제껏 정들었던? 윈도우 2008 을 지우고 윈도우 7 을 설치하기로 맘먹었다.. 그리고 설치했다.
오우.. 깔끔 해진 UI 보다는 부팅 속도 외, 이것저것 꽤 맘에 드는 부분들이 있지만, 역시 우분투 보다는 속도도 느리고 그래픽 적으로 그닥 뛰어난다고는 별로 느껴지지는 않았다. 그래서 다시 우분투로 부팅해야지.. 하고 리부팅을 했는뎀..
악.. 뭐삼?
예전엔 grub 로더에서 부팅 옵션이 나왔는데.. 이젠 안나오는거다.. 아우.. 다시 부팅된 윈도우 7 에서 하드를 살펴보니 파티션이 나간건 아닌거 같아 부랴부랴 인터넷을 찾아봤다.
1. 우분투를 설치했던 사람들이라면 설치 시디나 USB 가 있을 것이다. 이를 이용하여 Ubuntu 를 설치 않고 둘러보기.. 였나? 뭐 여하튼 젤 첨 옵션을 선택하여 시디나 USB 로 부팅하여 우분투를 일단 시작한다.
2. 우분투가 시작한 뒤 터미널을 열어 아래 명령어들을 적는다.
sudo grub
grub> find /boot/grub/stage1
-----------------------------------> 리턴값 (hdX,Y)
명령어를 치면 우분투 파티션이 보여진다. 내 경우는 (hd0, 1) 로 보였다. 그런 뒤 아래 명령어 들을 쳐준다.
grub> root (hd0,1)
grub> setup (hd0)
grub> quit
자 Grub 이 설치 되었다. 재부팅을 하면 항상 봐왔던.. 반가운.. Grub 로더가 보이고, 우분투와 non-linux OS 인 윈도우 비스타라고 씌여있는 옵션이 보일 것이다. (뭐삼? 윈도우 7 인뎀.. )
자 우분투로 부팅이 잘 되었다면 터미널에서
sudo gedit /boot/grub/menu.lst
입력하여 menu.lst 를 연 뒤 맨 아래 있는 부분을 수정해 준다.
title windows 7 (Loader) <--- 요 부분이 windows vista 로 적여있었다.
root (hd0,1) <---- 요 부분은 다를 수 있다. 난 menu.lst 에 있는 그대로 놔두었음.
savedefault
makeactive
chainloader +1
뭐.. 그냥 로더 옵션 중 windows vista 를 windows 7 으로 바꾸는 작업일 뿐, 상관없이 부팅은 잘 된다.
여하튼, 고치고 난 뒤 다시 재부팅을 하면 윈도우 7 이라는 옵션이 보이고, 부팅 윈도우 7 으로도 부팅이 잘 된다.
웹페이지를 만들면서 많이 사용하게 되는 드롭다운 리스트를 루비 온 레일즈에서는 아래와 같은 방법으로 많이 사용합니다.
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
포럼들을 여기 저기 에서 읽어 보다 보니 Collection_Select 에서의 onChnage 관련해서 질문이 많이 올라오길래 잠시 정리해 봅니다.
Collection_Select (출처: http://api.rubyonrails.org/ )
object : 현 모델의 객체입니다.
method : 현 모델에서 사용하는 함수나 테이블의 컬럼 이름 입니다.
collection : 드롭다운 리스트에 뿌릴 멤버를 들고 있는 컬렉션입니다.
value_method : 컬렉션의 멤버이자 option value 값입니다.
text_method : 컬렉션의 멤버이자 드롭다운 리스트에 보이는 글자 입니다.
options = {} : :prompt:include_blank 값을 넣습니다.
html options={} : 자바 스크립트나 html 옵션을 넣을 수 있습니다.
예) 아래 두개의 문장 모두 같은 결과를 냅니다.
1) <%= collection_select :productorigin_form, "national_id", @national, :id, :NationName, {:prompt => "Country Select"}, {:onchange=> "alert(id)"} %>
2) <%= productorigin_form.collection_select "national_id", @national, :id, :NationName, {:prompt => "Country Select"}, {:onchange=> "alert(id)"} %>
이렇게 하면 아래와 같은 html 이 만들어지며 나라를 선택할때 마다 "product_new_productorigin_attributes__national_id" 의 메세지 박스가 뜹니다.
카페 홈페이지를 만들면서 겪은 경험 중 하나는 데이터 테이블의 구조를 변경해야 하는 일이 있어서 몇자 적어보기로 했다.
제품 등록 부분이였는데, 이부분은 요구사항을 듣고, 그닥 어렵지 않게 구현되었다.
입력하고, 보여주고 업데이트 하고 지우는 정도인 간단하게 명령어 하나로 끝내버렸다.
그러나.. ㅡ,.ㅡa
일요일날 카페 친구와 이야기를 나누던 중, 제품(products) 관련 부분이 상당히 중요한 부분에서 잘못 이해되고 만들어 졌다는걸 알게 되었다.
초기에 받았던 요구 사항 중
1. 고객은 6개월, 12개월 단위로 한꺼번에 주문을 할 수 있어야 한다. (가격은 관리자가 직접 입력한다.)
(이해) 각각의 커피를 6개월치, 12개월 치를 한꺼번에 주문한다.
2. 고객은 "이달의 커피" 를 커피 리스트 상단에서 볼 수 있어야 한다.
(이해) 이달의 커피로 선정된 커피가 따로 상단에 올라간다.
3. 고객은 "샘플러" 혹은 프로모션 으로 관리되는 커피를 구입 할 수 있어야 한다.
(이해) 따로 이벤트 커피세일로 관리하여 제품리스트와는 별도로 관리한다.
이야기를 나누던 중, 위의 요구사항 부분이 틀렸다는걸 알았다.
1. 고객은 6개월 제품을 구입하면, 6개월 간 MD 추천의 다른 커피를 매달 받을 수 있어야 한다.
2. 고객은 커피 리스트 상단에 보이는 (MD 추천된) "이달의 커피" 로 받을 커피를 확인 할 수 있다.
3. 샘플러 커피나 프로모션 커피는 이벤트 커피 세일이 아닌 하나의 제품으로 팔려야 한다.
음.. 이런 이런 일이 생기다니.. 커헐..
서로 함께 이야기 하면서 같은 부분을 이정도로 다르게 이해 전달을 잘못 받을 수 있다는거에 충격을 먹었다.
(내 경험이 그닥 많지 않으므로.. ㅋㅋ) 여하튼, 그럼 수정에 들어가야 한다.
그럼 틀리게 만들어진 products 테이블을 보기로 하자. (200903230948203948_create_products.rb)
위의 테이블을 보면, 정말 성의 없이 만들어 진걸 알 수 있다. ㅡ,.ㅡ (챙피해..)
뭐 여하튼 챙피 하지만 잘못된 테이블이니 잘 만들어야 겠다.
(200903230948203948_create_products.rb) 파일 내 붉은 글씨 부분들은 이제 필요없는 부분들이다.
그리고 파란색 부분은 새로 추가 되어야 할 컬럼들이다.
products 테이블 외에도 필요한 새로운 테이블이 2개 생겼다.
1. productorigin: 나라와 농장, 그리고 제품 아이디를 가지고 있는 테이블
2. price : 제품 아이디 당 각각의 무게에 대한 가격을 들고 있는 테이블
그리고 공통 코드 테이블내에 product_type 이 추가 되게 되었다. : Normail, Sampler, CoffeeMonthly
자.. 그럼 서로의 관계는..
1. product has many product origins
2. product origins has one product
3. proudct has many price
4. price has one product
5. product origin has many nationals farms
6. nationals, farms has many product origins
자 그럼.. alter table을 해보기로 하자.
$/ruby script/generate migration change_product
위의 명령어를 쳐서 db/migrate/2009023948029_change_product.rb 파일을 만든 뒤
def self.down
remove_column :products, :name, :product_type
end
end
up 과 down 쪽에 파란색 부분을 넣어준다. 솔직히 원상복귀를 위해서는 self.up 내에 있는 remove_column 에 있는 모든 컬럼을 self.down 내에 add_column 으로 만들어 줘야 한다. 하지만 이전으로 복귀하지 않을 생각에 새로이 추가된 컬럼 2개만 없애버리기로 했다.
ROR 의 migration 에서 지원되는 컬럽 타입 총 11개
:binary, :boolean, :date, :datetime, :decimal, :float, :integer, :string, :text, :time, :timestamp
옵션 3개
:null => true 혹은 false, :limit => size 즉 크기, :default => value 값
demimal 컬럼 타입만을 위한 옵션 2개
:precision => 소수점자리, :scale => 소숫점 자리 위치
ex) :precision => 5, :scale => 0 로 정하면 -99,999 에서 +99,999
:precision => 5, :scale => 2 로 정하면 -999.99 에서 +999.99
Users={"dhh"=>"secret"}before_filter:authenticatedef indexrender:text=>"You needed a password to see this…"end privatedef authenticaterealm="Application"authenticate_or_request_with_http_digest(realm)do|name|Users[name]endendend
RubyonRails.Org 에서 소개된 샘플 코드를 보면, authenticate 은 Users 해쉬 를 HTTP Digest Auth 요청을 받아 진행하게 되어 있다.
해쉬를 부를때 아무런 값을 넣지 않고 불러오게 되면 "Nil" 이 리턴이 된다. Rails 의 digest authentication 루틴에서는 nil 에 대한 반응으로 authentication 실패로 받아들인다. 하지만 암호(password) 가 빈칸으로 제공이 된다면.. 입력된 nil 과 리턴된 nil 이 즉 nil==nil 이 되어 실패 값이 아닌 성공값이 되어 인증 성공이 되어 버린다.
2.3 Ruby on Rails 에서 위의 방법으로 인증을 거친다면, 사용자 이름 및 암호에 아무런 값을 넣지 않아도 인증 성공이 되어 버린다.
예로 http://authbroken.heroku.com/ 싸이트를 방문하면 인증을 거치는데 그냥 확인을 누르게 되면 "you needed a password to see this... ( 암호를 넣어야 볼 수 있는 페이지 입니다..." 라는 문구를 볼 수 있다.
Ruby on Rails 의 Core 팀에서 만들어진 패치는 아니지만, 실질적으로 아래 링크된 패치를 적용시켜 인증에 대한 위험 요소를 줄여야겠다.
패치된 내용은 password_procedure 에서 nil 을 반환하면 validate_digest_response 에서 false 를 반환하도록 바꾸었다고 한다.
log 2 번째 이다. 이번엔 동적 드롭다운(dynamic dropdown) 을 해보려 했다.
기본적이기 때문에 인터넷에 도움말들이 많았고, 원하는 내용을 RailsCasts 에서 찾을 수 있었다.
dynamic select 를 사용하여 만드는 Rails 에서의 첫번째 dynamic dropdown 이다.
"제품 등록" 사용자 스토리 중 다음은 동적 드롭다운을 사용하는 부분이다.
1. 제품을 선택할 때 원산지(나라) 와 농장을 선택한다.
2. 원산지(나라)를 선택하면 농장 선택을 할 수 있는데, 그 나라에 해당하는 농장이 보여주어야 한다.
간단한 스토리이다. 하지만 처음 접하는 레일즈에서 어떻게 구현을 해야 할지 난감 했다.
Log 1 을 보면 dropdown list 구현 방법이 나와 있는데, 나라 리스트의 이벤트를 받아 나라 코드를 가지고 해당 농장을 보여주는 간단한 구현을 railscasts 에 나와 있는데로 자바 스크립트를 사용하였다.
모든 농장 리스트를 자바 스크립트에서 받아 DOM 로드 후 (원산지) 나라 리스트의 이벤트를 기다린다.
이벤트가 일어나며 농장 리스트에서 이벤트 시 나라 코드가 일치된 농장 리스트만을 배열에 넣어 농장 등롭 다운 리스트에 보여준다.
등록될 나라들의 농장 리스트가 그리 많지 않기에, 원산지 나라 리스트에서 이벤트를 매번 받아 서버에 접속하는 것 보다는 클라이언트 쪽에서 리스트를 들고 있다가 보여주는게 효율적이라 판단되었다.