'OS > LINUX' 카테고리의 다른 글
sendmail 설정후 외부메일 안들어올때 -0- (0) | 2006.02.21 |
---|---|
[본문 스크랩] RedHat(레드햇) 9 설치 후 yum 설치 (0) | 2006.02.21 |
[펌] ssh brute-force 공격에 대한 설명과 대응 방법 (0) | 2006.02.02 |
헛... 아파치에 이런게... 스팸어쌔신 (0) | 2005.11.02 |
피싱 사이트 -.- (0) | 2005.09.22 |
sendmail 설정후 외부메일 안들어올때 -0- (0) | 2006.02.21 |
---|---|
[본문 스크랩] RedHat(레드햇) 9 설치 후 yum 설치 (0) | 2006.02.21 |
[펌] ssh brute-force 공격에 대한 설명과 대응 방법 (0) | 2006.02.02 |
헛... 아파치에 이런게... 스팸어쌔신 (0) | 2005.11.02 |
피싱 사이트 -.- (0) | 2005.09.22 |
□ 개요
o 최근 일반 PC 사용자들이 해킹당한 홈페이지를 방문만 하여도 악성 코드에 감염시키는 웹 해킹 사고가
지속되고 있어 웹서버 예방 및 대책이 필요합니다.
□ 피해 예방
o SQL Injection 취약점 제거
- 사용자 입력값이나 URL 인자값에 특수문자( " / \ ; : Space -- +등)와 SQL 구문(or, and, union,
select, insert 등)이 포함되어 있는지 검사하여 허용되지 않은 문자열이나 문자가 포함된 경우 차단
- SQL 서버의 에러 메시지를 사용자에게 보여주지 않도록 설정
※ 공격자는 리턴 되는 에러 메시지에 대한 분석을 통하여 공격에 성공할 수 있는 SQL Injection 스트링을
알아낼 수 있음
o 불필요한 확장 저장 프로시져 제거
- MS-SQL 서버에서 제공하고 있는 확장 저장 프로시져 중 사용하지 않는 프로시져들을 제거
- xp_cmdshell, xp_regread, xp_dirtree와 같은 프로시져들은 공격자에 의해 이용될 수 있으므로 가능한
제거하는 것이 바람직함
o 관리자 페이지에 대한 접근 통제
- 관리자 로그인 페이지 주소를 유추하기 어려운 이름으로 변경하고, 아래와 같은 유추 가능한 이름을 관리자
페이지로 사용하는 것을 금지
. http://admin.victim.com
. http://www.victim.com/admin/
. http://www.victim.com/manager/
. http://www.victim.com/master/
. http://www.victim.com/system/
- 관리자 PC에서만 홈페이지 관리자 페이지에 접근할 수 있도록 IP별 접근통제 실시
□ 공격 탐지
o 주기적인 로그 분석
- 최근 발생되고 있는 사고는 SQL 공격 흔적이나 공격자의 행위 등이 IIS 웹 로그에 남으므로 로그를
주기적으로 검사하여 공격자에 의한 침입여부를 확인
- 공격시 아래와 같은 DB 에러 및 SQL 명령 수행 흔적이 남음
2005-06-11 17:23:02 xxx.xxx.xxx.xxx - victim_IP 80 GET /announce/new_detail.asp
id=529|27|80040e14|[Microsoft][ODBC_SQL_Server_Driver][SQL_Server]
Unclosed_quotation_mark_before_the_character_string_. 500 Mozilla/4.0+
(compatible;+MSIE+6.0;+Windows+NT+5.2;+SV1;+.NET+CLR+1.1.4322)
2005-06-11 17:23:34 xxx.xxx.xxx.xxx - victim_IP 80 GET /announce/new_detail.asp
id=529;DELETE%20bb;Insert%20bb%20exec%20master..xp_dirtree%20C:\,1,1-- 200
Microsoft+URL+Control+-+6.00.8862
o 홈페이지 초기화면에 iframe 삽입여부 점검
- 공격이 성공할 경우 홈페이지 초기 화면에 특정 사이트로 링크되도록 악성코드를 삽입하지만, 공격에
이용되는 화면의 사이즈를 0과 같이 작게 하여 화면상으로는 확인이 어려움
- 따라서, 공격 사실을 확인하기 위해서는 다음과 같이 초기화면 소스에 비정상적인 iframe이 삽입되어
있는지 점검
iframe src ="http://www.xxx.xx.xx/123/123/index.htm" name ="A" width="0" frameborder="0"
□ 참고 자료
o 웹 해킹을 통한 악성코드 유포 사이트 사고 사례
http://www.krcert.or.kr/report/download.jsp?no=IN2005012&seq=0
o 홈페이지 개발 보안 가이드
http://www.kisa.or.kr/news/2005/announce_20050427_submit.html
아파치 튜닝 정리 (0) | 2007.01.19 |
---|---|
[펌]아파치 + 톰캣 연동 (0) | 2006.09.25 |
Apache 모듈 중 mod_expires -- 이미지 캐시 (0) | 2006.02.22 |
[펌] [weblogic] 웹로직 문제점 방안 (0) | 2006.02.07 |
[펌] Tomcat 클러스터링 (0) | 2004.05.19 |
출처 : http://dreamnow.co.kr/tech/Log4.asp
|
||||||||||||||||||||||||||||||||||||||
|
윈도우에서 사용할 수 있는 메일서버 (0) | 2008.10.23 |
---|---|
분산파일 시스템 (0) | 2006.06.21 |
[익스체인지 서버 2003, 바뀐 점은] ③ ISA 서버 2004.. (0) | 2006.05.26 |
[익스체인지 서버 2003, 바뀐 점은] ① 스팸메일 탈출 .. (0) | 2006.05.26 |
[익스체인지 서버 2003, 바뀐 점은] ② 웹으로 아웃룩 .. (0) | 2006.05.26 |
<그림 1. jms 시스템 개념도>
<그림 2. jms 시스템 개념도>
<그림 3. JMS Queue의 개념>
<그림 3-1. 포탈 쇼핑몰이 늘어난 경우>
http://xfire.codehaus.org/ (0) | 2006.11.01 |
---|---|
[JavaSE]EJB 3.0을 이용한 웹 서비스 개발 & 커스텀 빈을 이용한 GlassFish 관리 시스템 확장 (0) | 2006.06.02 |
[링크] Oracle sample-code (0) | 2005.08.19 |
[링크]SmartClient (0) | 2005.08.10 |
[테크팁] JAX-RPC를 사용하여 간단한 웹서비스 구현하기& JAXB로 RELAX .. (0) | 2005.08.04 |
[본문 스크랩] RedHat(레드햇) 9 설치 후 yum 설치 (0) | 2006.02.21 |
---|---|
[link] 로그 분석 프로그램 사이트 (0) | 2006.02.07 |
헛... 아파치에 이런게... 스팸어쌔신 (0) | 2005.11.02 |
피싱 사이트 -.- (0) | 2005.09.22 |
[펌] [Linux] 아파치 가상호스트(Apache VirtualHost) 설정하기 (0) | 2005.08.24 |
VK-X100 | |
리뷰는 이곳에 있다.
http://review.cetizen.com/vk-x100/
이 핸드폰으로 바꾼지 10일 가량 되었다.
사용 소감으로는...
전화벨 소리 무지무지 크고.. 진동은 또 어찌나 쎈지.. 마사지 받아두 될 정도로 쎄다.
무지무지하게 얇아서 청바지 뒷주머니에 넣어두 티도 안난다!!
하지만..
전화가 왔을때 소리가 점점 끊기기 시작하며 30초 정도 지나면 통화 불능상태로 빠지며
통화가 두절된다. 그러나 안테나 표시는 끝까지 올라가 있다.
그리고.. 수시로 리부팅이 되기때문에 절대로 긴 메세지나 게임은 못한다.
펌웨어 업그레이드로 해결된다고 하나, 업그레이드 해봤자 똑같다.
키패드는 무지무지하게 뻑뻑하여 손 끝으로 꾹꾹 눌러줘야 하며,
이렇게 누르다가 지문이 없어지던지 핸드폰 키패드가 벋겨지던지 할것 같다.
이 핸드폰은 누구는 다운현상이 전혀 없다고 하고, 나같은 사람은 수시로 다운되어서
성질 돋구게 한다.
정말 "뽑기 폰" 이 맞는것 같다.
서비스 센터에서 기계 교체 해 준다고 했는데 낼 연락 오려나~
[본문 스크랩] 이순신과 임진왜란 (신에게는 아직도 열두 척의 배가 .. (0) | 2006.02.15 |
---|---|
[펌] 꺅~넘 귀엽잖아! 우파루파 (2) | 2006.02.08 |
오늘 주문한 책. (0) | 2006.02.02 |
자동차 오토미션 전문수리점 (0) | 2006.02.01 |
20000 히트 이벤트!!! (2) | 2006.01.26 |
Spring 프레임워크 워크북 |
|
|
Ajax 입문 : Asynchronous JavaScript + XML |
|
|
[펌] 꺅~넘 귀엽잖아! 우파루파 (2) | 2006.02.08 |
---|---|
얇지만 이상한 휴대전화... (0) | 2006.02.02 |
자동차 오토미션 전문수리점 (0) | 2006.02.01 |
20000 히트 이벤트!!! (2) | 2006.01.26 |
[펌] MS 인터넷 익스플로러(IE)의 ActiveX 작동변경 내용 (0) | 2006.01.25 |
얇지만 이상한 휴대전화... (0) | 2006.02.02 |
---|---|
오늘 주문한 책. (0) | 2006.02.02 |
20000 히트 이벤트!!! (2) | 2006.01.26 |
[펌] MS 인터넷 익스플로러(IE)의 ActiveX 작동변경 내용 (0) | 2006.01.25 |
지금 읽고 있는 책, 시킨 책.. (0) | 2006.01.12 |
John Dyer
Dallas Theological Seminary
적용 대상:
Microsoft Visual Studio 2005 및 이전 버전
ASP.NET 1.1
C# 프로그래밍 언어
Visual Basic 프로그래밍 언어
요약: 리플렉션을 사용하여 단 한 줄의 코드로 비즈니스 개체를 ASP.NET Web Forms에 바인딩하면 복잡한 작업이 단순해지고 오류가 줄어듭니다.
MSDFormBinding.msi 샘플 파일을 다운로드하십시오.
소개
양식 코드 단순화 및 단축
시작하기: 리플렉션에서 속성 목록 검색
개체 속성 값을 컨트롤에 바인딩
알려진 속성을 사용하여 알려지지 않는 컨트롤 값 설정
프로세스를 반대로 수행: BindControlsToObject
성능 및 FormBinding 스키마 확장
결론
웹 개발자가 반복적으로 수행하는 가장 일상적인 작업 중 하나는 데이터베이스 테이블을 업데이트하는 간단한 폼을 작성하는 것입니다. 웹 개발자는 테이블의 레코드를 표시하는 목록 페이지와 각 데이터베이스 필드에 대한 적절한 폼 컨트롤이 있는 폼 페이지를 만듭니다. 또한 대부분의 개발자는 데이터베이스 테이블을 나타내는 비즈니스 개체를 사용하여 코드를 다계층 디자인으로 구성합니다. 비즈니스 개체(Document)가 데이터베이스 테이블(Documents)을 나타내는 경우 대부분의 폼은 아래 코드와 같습니다(이 기사에는 영문 페이지 링크가 포함되어 있습니다).
<script runat="server">protected void Page_Load(Object Src, EventArgs E) {if (!IsPostBack) { Document document = Documents.GetDocument(Request.QueryString["DocumentID"]); Title.Text = document.Title; Active.Checked = document.Active; CreatedDate.Text = document.CreatedDate.ToString(); AuthorID.FindByValue(document.AuthorID.ToString()).Selected = true; // ... 기타 등등 HtmlBody.Text = document.HtmlBody;}}protected void SaveButton_Click(Object Src, EventArgs E) { Document document = Documents.GetDocument(Request.QueryString["DocumentID"]); document.Title = Title.Text; document.Active = Active.Checked; document.CreatedDate = Convert.ToDateTime(CreatedDate.Text); document.AuthorID = Convert.ToInt32(AuthorID.SelectedItem.Value); // ... 기타 등등 document.HtmlBody = HtmlBody.Text; Documents.Update(document);}</script>(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사에는 설명을 위해 번역문으로 제공됩니다.)
위 코드에서 각 컨트롤은 명시적으로 캐스팅되어 폼 컨트롤의 올바른 속성으로 설정됩니다. 속성 및 폼 컨트롤 수에 따라서 이 코드 부분은 길이가 길어져 관리하기가 어려울 수 있습니다. 이 코드는 또한 형식 변환과 ListControl을 위한 오류 수정을 포함해야 하므로 더욱 복잡해집니다. 코드 생성 도구(예: Eric J. Smith의 뛰어난 CodeSmith )를 사용하여 폼을 만들어도 사용자 지정 논리가 필요한 경우에는 오류가 포함되기 쉽습니다.
리플렉션을 사용하면 코드를 한 줄만 사용하여 비즈니스 개체의 모든 속성을 해당 폼 컨트롤에 바인딩할 수 있으므로, 코드의 줄 수가 줄어들고 가독성이 향상됩니다. 리플렉션 시스템 빌드가 끝나면 위 코드는 다음과 같이 줄어듭니다.
protected void Page_Load(Object Src, EventArgs E) { if (!IsPostBack) { Document document = Documents.GetDocument(Request.QueryString["DocumentID"]); FormBinding.BindObjectToControls(document); }}protected void Save_Click(Object Src, EventArgs E) { Document document = Documents.GetDocument(Request.QueryString["DocumentID"]); FormBinding.BindControlsToObject(document); Documents.Update(document);}
이 코드는 모든 표준 ASP.NET 컨트롤(TextBox, DropDownList, CheckBox 등)과 대부분의 타사 컨트롤(예: Free TextBox 및 Calendar Popup )에서 작동합니다. 비즈니스 개체 속성과 폼 컨트롤의 수에 상관 없이, 폼 컨트롤 ID가 비즈니스 개체 속성 이름과 일치할 경우 동일한 한 줄의 코드가 모든 필수 기능을 처리합니다.
가장 먼저 해야 할 일은 비즈니스 개체의 속성을 검사하고 비즈니스 개체 속성 이름과 같은 ID를 가지는 ASP.NET 컨트롤을 찾는 것입니다. 아래 코드는 기본적인 바인딩 조회를 구성합니다.
public class FormBinding { public static void BindObjectToControls(object obj, Control container) { if (obj == null) return; Type objType = obj.GetType(); PropertyInfo[] objPropertiesArray = objType.GetProperties(); foreach (PropertyInfo objProperty in objPropertiesArray) { Control control = container.FindControl(objProperty.Name); if (control != null) { // 컨트롤을 처리합니다. } } }}
위 코드에서 BindObjectsToControls 메서드는 비즈니스 개체 obj 및 컨테이너 컨트롤을 받아들입니다. 컨테이너 컨트롤은 일반적으로 현재 WebForm의 Page 개체입니다. 런타임에 컨트롤의 중첩 순서를 변경하는 ASP.NET 1.x MasterPages 구현을 사용하는 중이면 폼 컨트롤이 상주하는 Content 컨트롤을 지정해야 합니다. 그 이유는 FindControl 메서드가 ASP.NET 1.x에서 중첩 컨트롤 및 명명 컨테이너와 작동하는 방식 때문입니다.
위 코드에서 비즈니스 개체의 Type을 가져오고 해당 Type을 사용하여 PropertyInfo 개체의 배열을 가져옵니다. 각 PropertyInfo 개체는 비즈니스 개체 속성에 대한 정보뿐 아니라 비즈니스 개체에서 값을 가져와 설정하는 기능도 포함합니다. foreach 루프를 사용하여 비즈니스 개체 속성 이름(PropertyInfo.Name)에 해당하는 ID 속성이 있는 ASP.NET 컨트롤의 컨테이너를 확인합니다. 컨트롤을 찾으면 속성 값을 컨트롤에 바인딩합니다.
대부분의 처리 작업은 이 단계에서 수행합니다. 발견된 Control을 개체의 속성 값으로 채워야 합니다. 이렇게 하는 방법 중 하나는 각 컨트롤 형식에 대해 if ... else 문을 만드는 것입니다. ListControl(DropDownList, RadioButtonList, CheckBoxList 및 ListBox)에서 파생되는 모든 컨트롤에는 일관되게 액세스할 수 있는 공용 인터페이스가 있으므로, 이러한 컨트롤을 그룹화할 수 있습니다. 발견된 컨트롤이 ListControl인 경우 컨트롤을 ListControl로 캐스팅한 다음 선택한 항목을 설정할 수 있습니다.
Control control = container.FindControl(objProperty.Name);if (control != null) { if (control is ListControl) { ListControl listControl = (ListControl) control; string propertyValue = objProperty.GetValue(obj, null).ToString(); ListItem listItem = listControl.Items.FindByValue(propertyValue); if (listItem != null) listItem.Selected = true; }else { // 다른 컨트롤 형식을 처리합니다. }}
애석하게도 다른 컨트롤 형식은 부모 클래스에서 파생되지 않습니다. 여러 일반 컨트롤(TextBox, Literal 및 Label)에는 모두 .Text 문자열 속성이 있지만, 속성이 공용 부모 클래스로부터 파생되지 않으므로 각 컨트롤 형식을 개별적으로 캐스팅해야 합니다. 또한 Calendar 컨트롤과 같은 다른 컨트롤 형식을 캐스팅해야 하는데 이는 적절한 속성(Calendar의 경우에는 SelectedDate 속성)을 사용하기 위해 필요합니다. 모든 표준 ASP.NET 폼 컨트롤을 포함하고 폼 컨트롤의 올바른 속성에 액세스하는 데 굉장히 많은 코드 줄이 필요한 것은 아닙니다.
if (control is ListControl) { ListControl listControl = (ListControl) control; string propertyValue = objProperty.GetValue(obj, null).ToString(); ListItem listItem = listControl.Items.FindByValue(propertyValue); if (listItem != null) listItem.Selected = true;} else if (control is CheckBox) { if (objProperty.PropertyType == typeof(bool)) ((CheckBox) control).Checked = (bool) objProperty.GetValue(obj, null);} else if (control is Calendar) { if (objProperty.PropertyType == typeof(DateTime)) ((Calendar) control).SelectedDate = (DateTime) objProperty.GetValue(obj, null);} else if (control is TextBox) { ((TextBox) control).Text = objProperty.GetValue(obj, null).ToString();} else if (control is Literal)( //... 기타 등등(레이블용 등)}
이 방식에서는 표준 ASP.NET 1.x 컨트롤을 적절하게 다루고 있습니다. 이제 완전한 기능을 하는 BindObjectToControls 메서드를 사용할 수 있습니다. 그러나 이 방법은 기본 제공 ASP.NET 1.x 컨트롤만을 고려하므로 적용에 있어 제한적입니다. 새 ASP.NET 2.0 컨트롤을 지원하거나 타사 컨트롤을 사용하려면 FormBinding 프로젝트에서 컨트롤의 어셈블리를 참조하고 if ... else 목록에 컨트롤 형식을 추가해야 합니다.
이 문제에 대한 해결 방법은 또 다른 리플렉션을 사용하여 각 컨트롤의 속성을 검색하고, 비즈니스 개체 속성의 유형에 해당하는 속성 유형이 컨트롤에 있는지 확인하는 것입니다.
위에서 언급한 것처럼 여러 컨트롤은 문자열 속성 .Text를 공유하며 대부분의 폼 컨트롤은 이 속성을 기본적으로 동일한 방식으로 사용합니다. 즉, 사용자가 입력하는 데이터를 가져와 설정하는 데 사용하는 것입니다. 그 외에도 다양한 컨트롤에 사용되는 기타 일반 속성 및 속성 유형이 있습니다. 이러한 속성 중 몇 가지를 예로 들면, 여러 일정 및 날짜 선택 컨트롤에서 사용되는 .SelectedDate라는 DateTime 속성, 부울 컨트롤에서 사용되는 .Checked라는 부울 속성, 숨겨진 컨트롤에서 일반적으로 사용되는 .Value라는 문자열 속성 등이 있습니다. 이러한 네 개의 속성(string Text, string Value, bool Checked 및 DateTime SelectedDate)은 가장 일반적인 컨트롤 속성입니다. 컨트롤 형식에 상관 없이 이러한 속성에 바인딩되는 시스템을 디자인할 수 있다면 Binding 메서드는 이러한 네 개의 속성을 사용하는 모든 컨트롤에 적용됩니다.
아래 코드에서는 일반적으로 사용되는 속성을 포함하는지 확인하기 위해 리플렉션을 다시 사용합니다. 그러나 이번에는 비즈니스 개체가 아닌 폼 컨트롤에서 사용합니다. 이러한 속성이 포함된 경우 비즈니스 개체의 속성 값을 컨트롤의 속성으로 설정합니다. 예를 들어 PropertyInfo 배열을 반복하여 .Text라는 문자열 속성을 찾습니다. 컨트롤에 이 속성이 있으면 비즈니스 개체에서 해당 컨트롤의 속성으로 데이터를 보냅니다.
if (control is ListControl) { // ...}else { // 컨트롤의 형식과 속성을 가져옵니다. // Type controlType = control.GetType(); PropertyInfo[] controlPropertiesArray = controlType.GetProperties(); // .Text 속성을 찾습니다. // foreach (PropertyInfo controlProperty in controlPropertiesArray) { if (controlPropertiesArray.Name == "Text" && controlPropertiesArray.PropertyType == typeof(String)) { // 컨트롤의 .Text 속성을 설정합니다. // controlProperty.SetValue(control, (String) objProperty.GetValue(obj, null), null); } }}
.Text가 발견되면 PropertyInfo 클래스의 GetValue 메서드를 사용하여 비즈니스 개체의 속성에서 값을 검색합니다. 그런 다음 컨트롤의 .Text 속성에 대한 SetValue 메서드를 사용합니다. 여기서는 또한 컨트롤의 속성을 typeof(String)로서 형식 검사하고 (String) 표기법을 사용하여 속성에서 값을 명시적으로 캐스팅합니다.
BindObjectToControls 메서드를 완성하기 위해 다른 일반 속성인 .Checked, .SelectedDate 및 .Value도 처리해야 합니다. 아래 코드에서는 코드를 단순화하기 위해 컨트롤 속성 검색을 FindAndSetControlProperty라는 도우미 메서드에 래핑합니다.
if (control is ListControl) { // ...}else { // 컨트롤의 속성을 가져옵니다. // Type controlType = control.GetType(); PropertyInfo[] controlPropertiesArray = controlType.GetProperties(); bool success = false; success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "Checked", typeof(bool) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "SelectedDate", typeof(DateTime) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "Value", typeof(String) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "Text", typeof(String) );}private static void FindAndSetControlProperty(object obj, PropertyInfo objProperty, Control control, PropertyInfo[] controlPropertiesArray, string propertyName, Type type) { // 컨트롤 속성을 반복합니다. foreach (PropertyInfo controlProperty in controlPropertiesArray) { // 일치하는 이름과 형식을 확인합니다. if (controlPropertiesArray.Name == "Text" && controlPropertiesArray.PropertyType == typeof(String)) { // 컨트롤의 속성을 비즈니스 개체 // 속성 값으로 설정합니다. controlProperty.SetValue(control, Convert.ChangeType( objProperty.GetValue(obj, null), type) , null); return true; } } return false;}
일부 컨트롤에는 위 속성 중 둘 이상이 있을 수 있지만 여기서는 하나의 속성만 설정할 것이므로 위 속성 검사의 순서가 중요합니다. 예를 들어 CheckBox 컨트롤에는 .Text 및 .Checked 속성이 모두 있습니다. 이 경우에는 .Checked 속성만 사용하고 .Text 속성을 사용하지 않을 것이므로 속성 검색 순서에서 .Checked를 앞에 둡니다. 각 경우에서 이름과 형식이 올바른 컨트롤 속성을 찾으면 컨트롤의 속성을 비즈니스 개체 속성의 값으로 설정합니다.
이 시점에서 BindObjectToControls 메서드는 완전하게 기능을 수행합니다. 이 메서드는 임의의 클래스와 컨트롤 조합을 사용하여 ASPX 폼 위의 어떤 위치에서나 호출할 수 있습니다. 이제 폼을 제출할 때 이와 반대의 기능을 수행하는 메서드를 만들어야 합니다. 컨트롤 속성의 값을 비즈니스 개체 값으로 설정하는 대신에 컨트롤에서 사용자의 입력을 나타내는 새 값을 검색해야 합니다.
BindControlsToObject 메서드에서는 앞서 수행한 것과 동일한 방식으로 비즈니스 개체에서 속성 목록을 검색하고 FindControl 메서드를 사용하여 개체 속성과 일치하는 ID를 가진 컨트롤을 찾습니다. 해당 컨트롤을 찾으면 값을 검색하여 비즈니스 개체에 반환합니다. 이 섹션에는 또한 ListControl에 대한 별도의 코드도 포함됩니다. ListControl에는 공용 인터페이스가 있기 때문입니다. 이 컨트롤에서 값을 검색하여 비즈니스 개체에 반환하기 위해 또 다른 도우미 메서드를 사용합니다.
public static void BindControlsToObject(object obj, Control container) { Type objType = obj.GetType(); PropertyInfo[] objPropertiesArray = objType.GetProperties(); foreach (PropertyInfo objProperty in objPropertiesArray) { if (control is ListControl) { ListControl listControl = (ListControl) control; if (listControl.SelectedItem != null) objProperty.SetValue(obj, Convert.ChangeType(list.SelectedItem.Value, objProperty.PropertyType), null); }else { // 컨트롤의 속성을 가져옵니다. // Type controlType = control.GetType(); PropertyInfo[] controlPropertiesArray = controlType.GetProperties(); bool success = false; success = FindAndGetControlProperty(obj, objProperty, control, controlPropertiesArray, "Checked", typeof(bool) ); if (!success) success = FindAndGetControlProperty(obj, objProperty, control, controlPropertiesArray, "SelectedDate", typeof(DateTime) ); if (!success) success = FindAndGetControlProperty(obj, objProperty, control, controlPropertiesArray, "Value", typeof(String) ); if (!success) success = FindAndGetControlProperty(obj, objProperty, control, controlPropertiesArray, "Text", typeof(String) ); } }}private static void FindAndGetControlProperty(object obj, PropertyInfo objProperty, Control control, PropertyInfo[] controlPropertiesArray, string propertyName, Type type) { // 컨트롤 속성을 반복합니다. foreach (PropertyInfo controlProperty in controlPropertiesArray) { // 일치하는 이름과 형식을 확인합니다. if (controlPropertiesArray.Name == "Text" && controlPropertiesArray.PropertyType == typeof(String)) { // 컨트롤의 속성을 비즈니스 개체 // 속성 값으로 설정합니다. try { objProperty.SetValue(obj, Convert.ChangeType( controlProperty.GetValue(control, null), objProperty.PropertyType) , null); return true; } catch { // 폼 컨트롤의 데이터를 // objProperty.PropertyType으로 // 변환할 수 없습니다. return false; } } } return true;}
이러한 두 개의 메서드가 완성되면 양식 코드 단순화 및 단축에서 설명한 것처럼 폼 구문이 간단해집니다. 모든 속성과 컨트롤에 대한 형식 변환 및 오류 수정은 자동으로 처리됩니다. BindObjectToControls 및 BindControlsToObject의 두 메서드를 사용하면 개발자는 매우 유연하게 폼을 작성할 수 있습니다. 또한 다음과 같은 몇 가지 일반적인 시나리오가 처리됩니다.
성능 저하가 발생한다는 사실을 고려할 때 일부 개발자는 리플렉션을 사용하는 것이 그만한 가치가 있는지 궁금해할 것입니다. 저는 int DocumentID, bool Active, DateTime Created, int CategoryID, String Title, string Author 및 String htmlText의 7개 속성이 있는 개체를 사용하여 테스트한 적이 있는데 이 테스트에서 BindObjectToControls는 약 1/3밀리초가 걸렸고 BindControlsToObject는 약 1밀리초가 걸렸습니다. 이러한 값은 루프에서 BindObjectToControls와 BindControlsToObject 메서드를 1000번 실행한 결과로 얻어진 것입니다. 일반적인 폼 추가 및 편집 시나리오에서 이 정도의 성능 저하는 심각한 문제를 야기하지 않습니다. 개발 속도와 유연성이라는 확실한 이점의 대가로는 충분한 것이죠.
이 메서드는 거의 모든 폼에서 작동하지만 경우에 따라서는 위 코드를 수정해야 할 수도 있습니다. 일부 시나리오에서 개발자는 위 속성 중 하나를 기본 인터페이스로 사용하지 않는 컨트롤을 사용할 수 있습니다. 이 경우에는 해당 속성과 유형을 포함하도록 FormBinding 메서드를 업데이트해야 합니다.
두 개의 FormBinding 메서드인 BindObjectToControls 및 BindControlsToObject를 사용하면 양식 코드를 매우 단순하게 만들 수 있으며 최대한 유연하게 ASP.NET 폼을 개발할 수 있습니다. 이러한 사실이 저에게 도움이 된 것처럼 여러분께도 도움이 되기를 바랍니다.
John Dyer는 Dallas Theological Seminary 의 수석 웹 개발자로 일하면서 Telligent Systems 의 Community Server에 구축되어 있는 저명한 온라인 교육 프로그램을 관리하고 있습니다. 또한 널리 사용되고 있으며 모든 사람에게 무료로 제공되는 FreeTextBox ASP.NET HTML 편집기를 만들었습니다. 여가 시간에는 DTS에서 신학 석사 과정을 공부하고 있으며, 2005년 1월 1일에 결혼할 예정입니다.
[펌] .NET 2.0 이상... Mail Body 에 이미지를 포함하여 발송.. (0) | 2008.04.10 |
---|---|
VISUAL STUDIO Theme Gallery (0) | 2008.03.20 |
[펌] HTTP 모듈과 처리기를 사용하여 플러그형 ASP.NET 구성 요소 만.. (0) | 2006.02.01 |
[펌] Smart Client를 이용한 파일 업로드 (0) | 2006.01.18 |
ASP.NET 에서 EventLog 이용할 경우 어드민 권한으로 가장하기.. (0) | 2006.01.17 |
Scott Mitchell, 4GuysFromRolla.com
Atif Aziz, Skybow AG
2004년 9월
요약: 이 기사에서는 Scott Mitchell과 Atif Aziz가 HTTP 모듈과 처리기를 사용하여 오류 로깅을 ASP.NET 응용 프로그램에 추가하는 방법에 대해 설명합니다.
MSDNElmah.msi 샘플 파일을 다운로드하십시오.
소개
ELMAH: Error Logging Modules And Handlers
HTTP 처리기 및 모듈에 대한 간략한 개요
ELMAH의 아키텍처 검토
ASP.NET 웹 응용 프로그램에 ELMAH 추가
결론
참고 자료
관련 서적
ASP.NET 응용 프로그램에서 작업을 수행한 적이 있으며 다른 ASP.NET 응용 프로그램에서 간편하게 재사용할 수 있도록 유용한 일부 기능 집합을 디자인한 적이 있으십니까? ASP.NET은 다른 유형의 기능을 구성 요소화하기 위한 다양한 도구를 제공합니다. ASP.NET에서의 재사용을 위한 가장 일반적인 두 가지 도구는 다음과 같습니다.
별다른 주목을 끌지 못하는 두 개의 ASP.NET 재사용 도구는 HTTP 모듈과 처리기입니다(이 기사에는 영문 페이지 링크가 포함되어 있습니다).
HTTP 처리기와 모듈에 익숙하지 않더라도 걱정하실 필요는 없습니다. 이 기사의 뒷부분에서 좀더 자세하게 설명할 것입니다. 지금은 우선 ASP.NET 리소스 요청 도중에 발생하는 이벤트에 응답하여 실행하도록 구성할 수 있는 HTTP 모듈과 클래스에 대해 살펴보겠습니다. HTTP 처리기는 특정 리소스나 특정 유형의 리소스를 렌더링하는 클래스입니다. 실제로 ASP.NET 웹 페이지를 프로젝트에 추가할 때마다 필수적으로 HTTP 처리기를 작성하게 됩니다. 이는 ASP.NET 웹 페이지의 HTML 부분이 런타임에 동적으로 컴파일될 때 결과적으로 HTTP 처리기가 구현되는 System.Web.UI.Page
에서 직접 또는 간접적으로 상속이 이루어지기 때문입니다. 이것은 인라인 전략을 사용하는지 아니면 코드 숨김 전략을 사용하는지와는 무관합니다.
아시다시피 ASP.NET 응용 프로그램은 일반적으로 최종 사용자의 브라우저에서 요청 시에 호출되는 웹 페이지 집합으로 구성됩니다. ASP.NET 개발자가 작성하는 대부분의 코드는 특정 웹 페이지에 대한 요청과 관련됩니다. 예를 들면 일부 검색 쿼리에 기초하여 데이터베이스 결과를 표시하기 위한 특정 페이지의 코드 숨김 클래스에 있는 코드 등이 이에 속합니다. 그러나 경우에 따라서는 단일 웹 페이지와 관련된 코드, 즉 응용 프로그램의 모든 페이지에 적용되는 코드를 작성해야 할 수도 있습니다. 예를 들어 각 사용자가 웹 사이트에서 이동한 순서를 추적해야 할 수 있습니다. 이렇게 하려면 요청 시간과 사용자를 식별하는 정보가 각 페이지에 기록되도록 해야 합니다.
이러한 로깅 기능을 제공하는 방법 중 하나는 사이트의 각 웹 페이지에 대해 Page_Load
이벤트 처리기에서 관련 데이터를 데이터베이스에 기록하는 코드를 추가하는 것입니다. 그러나 이 방법은 유지 관리하거나 재사용하는 데 어려움이 있습니다. 사이트에서 새 ASP.NET 페이지를 추가할 때마다 적절한 로깅 코드가 포함되었는지 확인해야 합니다. 비슷한 기능을 다른 사이트에 추가하려는 경우 해당 사이트의 각 페이지에서 필요한 코드를 추가해야 합니다. 이상적인 경우라면 로깅 기능은 각 개별 페이지의 기능과 논리 및 물리적으로 구별되어야 하며 로깅 기능을 다른 사이트에 추가하는 것은 사이트의 /bin
디렉터리에서 어셈블리를 삭제하는 것만큼 간단할 것입니다.
이러한 재사용과 관리 용이성은 HTTP 모듈과 처리기를 통해 가능합니다. 이 기사에서는 오류 로깅을 매우 쉽게 관리하고 재사용할 수 있게 만들도록 설계된 일련의 HTTP 모듈과 처리기를 살펴보도록 하겠습니다. 이 기사의 목적은 HTTP 처리기와 모듈을 매우 높은 수준의 구성 요소화 형태로 사용함으로써 전체 기능을 웹 응용 프로그램과 무관한 단일 단위로 개발, 패키지화 및 배포할 수 있음을 보여 주는 것입니다. HTTP 처리기와 모듈을 통한 재사용 및 구성 요소화 이점을 사용하는 응용 프로그램이 이러한 목적을 설명하는 데 주로 사용됩니다.
이 기사에서 살펴볼 ELMAH(Error Logging Modules And Handlers(오류 로깅 모듈 및 처리기))는 공동 저자인 Atif Aziz(http://www.raboof.com/) 가 작성한 것이며, 오류 로깅 기능을 ASP.NET 웹 응용 프로그램에 간단하게 추가할 수 있는 방법을 제공합니다. ELMAH에서는 응용 프로그램 전체 로깅과 같은 웹 응용 프로그램 관련 코드를 위한 높은 수준의 구성 요소화를 HTTP 모듈과 처리기를 사용하여 제공하는 방법을 보여 줍니다. ELMAH는 플러그형 솔루션이므로 재컴파일이나 재배포할 필요 없이 실행 중인 ASP.NET 웹 응용 프로그램에 동적으로 추가할 수 있습니다.
특정 웹 응용 프로그램을 완벽하게 작성하고 테스트했더라도, 문제가 발생할 가능성은 여전히 존재합니다. 이것은 코드에 오류가 있기 때문이 아니라 전자 메일 서버가 응답하지 않거나 일부 데이터 손상으로 인해 암호화 오류가 발생하기 때문일 수 있습니다. 어떤 이유든 간에 예외가 발생할 경우 특히 라이브 사이트에서는 문제 진단을 지원하기 위해 예외에 대한 세부적인 정보를 기록하는 것이 중요합니다. ELMAH는 중앙화된 오류 로깅 및 알림을 위한 메커니즘을 제공합니다. ASP.NET 응용 프로그램에서 catch되지 않는 예외가 발생할 때마다 ELMAH는 알림을 받게 되며 Web.config 파일에 지정된 대로 예외를 처리합니다. 예외의 세부 정보를 데이터베이스에 기록하거나, 전자 메일을 관리자에게 보내거나, 두 작업을 모두 수행하는 것이 여기에 포함될 수 있습니다.
ELMAH는 처리되지 않은 예외에 적절하게 대응하도록 디자인된 것이 아니라 단순히 처리되지 않은 예외의 세부 정보만을 기록합니다. 따라서 ELMAH를 ASP.NET 웹 응용 프로그램에 추가하면 이 응용 프로그램에서 발생한 처리되지 않은 모든 예외가 기록됩니다. 처리되지 않은 예외가 발생하더라도 ELMAH는 최종 사용자의 작업에 영향을 주지 않습니다. 최종 사용자에게는 여전히 "서버 오류" 페이지가 표시되며, HTTP 500 오류를 처리하도록 사용자 지정 오류를 구성한 경우 다른 페이지로 이동합니다. 그러나 배후에서 ELMAH는 처리되지 않은 예외가 발생했음을 감지하고 세부 정보를 기록합니다.
ELMAH는 HttpApplication 개체의 Error 이벤트를 통해 처리되지 않은 예외를 검색합니다. Error
이벤트는 .NET 클래스 라이브러리 또는 ASP.NET 웹 페이지로부터의 요청을 처리하는 동안 catch되지 않은 예외가 버블링될 때마다 발생합니다. 많은 ASP.NET 응용 프로그램이 Server.ClearError() 메서드를 호출하여 사용자 지정 오류 페이지 및 처리를 잘못 구현한다는 점에 주의해야 합니다. 오류를 지우면 Error
이벤트가 발생하지 않을 뿐만 아니라 클라이언트에게 보고되지 않으므로 ELMAH는 예외를 기록할 수 있는 기회가 없습니다. 달리 말해서 사용자 지정 오류 페이지에서 ClearError()
를 사용하면 사용자는 문제가 발생했음을 알게 되지만 관리자 자신은 이러한 사실을 알 수 없습니다.
참고 사용자 지정 오류 페이지를 만드는 방법에 대한 자세한 내용은 Eli Robillard의 Rich Custom Error Handling with ASP.NET 기사를 참조하십시오.
참고 ASP.NET 웹 서비스에서 처리되지 않은 예외가 발생하면 Error
이벤트가 HTTP 모듈에 버블링되지 않으며, 따라서 ELMAH에도 버블링되지 않습니다. 대신에 ASP.NET 런타임이 예외를 인터셉트하고 SOAP 오류가 클라이언트에게 반환됩니다. 웹 서비스에서 오류가 기록되게 하려면 SOAP 오류를 수신 대기하는 SOAP 확장 을 만들어야 합니다.
처리되지 않은 예외의 세부 정보를 기록하는 것 외에도 오류 로그를 볼 수 있는 일련의 HTTP 처리기가 ELMAH에 포함되어 있습니다. 처리되지 않은 모든 오류의 목록뿐만 아니라 특정 오류에 대한 세부 정보를 볼 수 있는 로그에 대한 웹 인터페이스가 제공됩니다(그림 1 및 2 참조).
그림 1. 오류 로그 보기
그림 2. 오류 보기
또한 오류 로그를 RSS로 렌더링할 수 있습니다. 이렇게 하면 관리자는 오류가 발생했을 때 자신이 선호하는 RSS 애그리게이터를 통해 알림을 받을 수 있습니다(그림 3 참조).
그림 3. 오류의 RSS 피드
참고 Really Simple Syndication의 약어인 RSS는 뉴스 및 변경되는 기타 유형의 콘텐츠를 배포하는 데 널리 사용되는 XML 서식 표준입니다. RSS를 사용하여 콘텐츠를 배포하는 방법이나 웹 기반의 RSS 판독기를 만드는 방법을 비롯하여 RSS에 대한 자세한 내용은 Creating an Online News Aggregator with ASP.NET 을 참조하십시오.
이 기사에서는 간결하게 하기 위해서 주요 구성 요소를 중심으로 ELMAH의 일부 기능만 살펴봅니다. 전체 코드는 이 기사에서 다운로드할 수 있으며, 가능하면 전체 코드를 검토하여 구현 세부 정보를 확인하는 것이 좋습니다. 또한 http://workspaces.gotdotnet.com/elmah 에는 토론, 문제 보고, 최신 변경 내용 확인 등을 위한 ELMAH용 GotDotNet Workspace 설치 프로그램이 있습니다.
ASP.NET이 오류 로깅 및 보기 기능을 기본적으로 제공하지 않지만 Microsoft의 Patterns & Practices Group 은 오픈 소스 오류 로거인 EMAB(Exception Management Application Block) 를 만들었습니다. EMAB는 데스크톱 및 웹 기반 .NET 응용 프로그램에서 모두 작동하도록 설계되었지만, 기본적으로 EMAB가 예외 세부 정보를 Windows 이벤트 로그에 게시하기 때문에 EMAB는 주로 웹 응용 프로그램이 있는 데스크톱 응용 프로그램용으로 추가적으로 설계된 것처럼 보입니다. 이벤트 로그가 데스크톱 응용 프로그램의 간략한 예외 정보를 저장하기에 적절한 백업 저장소이기는 하지만 대부분의 웹 응용 프로그램, 특히 웹 호스팅 회사의 공유 서버에서 호스팅되는 응용 프로그램은 이벤트 로그를 사용하려 하지 않습니다. 이벤트 로그를 사용하려면 ASP.NET 응용 프로그램이 이벤트 로그에 기록할 수 있도록 특수한 권한을 설정해야 하기 때문입니다. 물론 EMAB는 데이터베이스에 정보를 기록하는 사용자 지정 게시자를 만들 수 있는 충분한 유연성을 제공하지만 이것은 개발자의 개입이 요구되는 별도의 작업 단계입니다.
참고 ELMAH는 Microsoft SQL Server 2000용의 데이터베이스 로깅 모듈을 제공합니다. 이에 대해서는 뒤에 설명할 것입니다. 또한 ELMAH를 사용하면 웹 서버의 파일 시스템에 있는 XML 파일에 예외 세부 정보를 기록하는 로거와 같은 사용자 지정 예외 로거를 만들 수 있습니다. 실제로, 사용하려는 EMAB에 대해 사용자 지정 게시자를 이미 작성한 경우에는 ELMAH를 확장하여 Exception Management Application Block을 사용할 수 있습니다.
EMAB를 사용하여 예외 정보를 기록하는 방법은 웹 응용 프로그램의 관리 용이성과 재사용 가능성에 큰 영향을 끼칩니다. 예를 들어 예외 정보를 기록하기 위한 간단한 방법은 각 ASP.NET 웹 페이지에서 각 코드 블록 주위에 try ...catch
블록을 배치하여 catch
섹션에서 EMAB를 호출하는 것일 수 있습니다.
private void Page_Load(object sender, EventArgs e) { try { // 예외를 일으킬
수 있는 코드 } catch (Exception ex) { // 예외 로거 라이브러리를 호출하여 예외 정보를
기록합니다. } }(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사
에는 설명을 위해 번역문으로 제공됩니다.)
이 방법은 각각의 모든 ASP.NET 웹 페이지에 예외 로깅을 긴밀하게 결합하기 때문에 관리 용이성이나 재사용 가능성이 전혀 없다는 점에서 매우 비효율적입니다. Global.asax의 Application_Error
이벤트에서 EMAB를 사용한다면 더 나은 방법이 될 것입니다. 이 방법은 예외 게시 코드가 각 ASP.NET 웹 페이지에 포함되는 대신에 중앙화된 단일 장소에 위치하기 때문에 관리 용이성과 재사용 가능성이 존재하는 더 느슨하게 결합된 아키텍처를 제공합니다. 이 방법의 단점은 플러그형이 아니라는 것입니다. 이 오류 로깅 기능을 다른 ASP.NET 웹 응용 프로그램에 추가하려면 응용 프로그램의 Global.asax
를 수정해야 하므로 응용 프로그램을 재컴파일 및 재배포해야 합니다.
이 기사에서 중점적으로 다루려는 내용은 EMAB를 대체하는 수단을 소개하는 것이 아니라 HTTP 처리기와 모듈을 통해 가능해지는 구성 요소화를 강조하려는 것입니다. ELMAH는 중앙화된 오류 로깅과 같은 일반적인 작업을 가져와 구성 요소화함으로써 쉽게 관리할 수 있게 만들고 높은 수준의 재사용 가능성을 제공하는 방법을 보여 줍니다. ELMAH의 목적은 적용 가능한 기능을 구성 요소화하는 것에 대한 지침을 제공하는 것입니다.
ELMAH의 아키텍처와 구현에 대한 구체적인 내용을 검토하기 전에 HTTP 처리기와 모듈을 잠깐 살펴보도록 하겠습니다. IIS 웹 서버에 요청이 도착하면 IIS는 요청의 확장을 검사하여 처리 방법을 결정합니다. HTML 페이지, CSS 파일, 이미지, JavaScript 파일 등의 정적 콘텐츠의 경우 IIS는 요청 자체를 처리합니다. ASP 페이지, ASP.NET 웹 페이지, ASP.NET 웹 서비스 등의 동적 콘텐츠의 경우 IIS는 요청을 지정된 ISAPI 확장에 위임합니다. ISAPI 확장은 특정 유형의 요청을 렌더링하는 방법을 알고 있는 관리되지 않는 코드입니다. 예를 들어 asp.dll
ISAPI 확장은 전통적인 ASP 웹 페이지의 요청을 렌더링하며 aspnet_isapi.dll
ISAPI 확장은 ASP.NET 리소스에 대한 요청이 있을 때 호출됩니다.
ISAPI 확장 외에도 IIS는 ISAPI 필터를 허용합니다. ISAPI 필터는 IIS에 의해 발생한 이벤트에 응답하여 실행할 수 있는 관리되지 않는 코드입니다. 요청 수명 주기 동안에 IIS는 해당 이벤트를 발생시키는 여러 단계를 거칩니다. 예를 들어 요청이 처음 IIS에 도달했을 때, 요청을 인증하려고 할 때, 렌더링된 콘텐츠를 다시 클라이언트에게 보내려고 할 때와 같은 여러 경우에 이벤트가 발생합니다. ISAPI 필터는 일반적으로 URL 재작성, 압축, 특수한 인증 및 권한 부여, 특수한 로깅 등의 기능을 제공하는 데 사용됩니다.
ASP.NET 리소스에 대한 요청은 IIS에 도달하면 ASP.NET 엔진에 라우팅되며 ASP.NET 엔진은 요청된 리소스에 대한 콘텐츠를 렌더링합니다. ASP.NET 엔진은 요청이 ASP.NET HTTP 파이프라인을 통과할 때 여러 이벤트를 발생시킨다는 점에서 IIS와 유사하게 작동합니다. 게다가 ASP.NET 엔진은 요청된 리소스의 렌더링을 특정 클래스에 위임합니다. IIS가 관리되지 않는 ISAPI 확장 및 필터를 사용하는 것과 달리 ASP.NET은 HTTP 처리기 및 모듈이라고 부르는 관리되는 클래스를 사용합니다.
HTTP 처리기는 특정 유형의 리소스를 렌더링하는 클래스입니다. 예를 들어 ASP.NET 웹 페이지를 위한 코드 숨김 클래스는 특정 웹 페이지의 태그를 렌더링하는 방법을 알고 있는 HTTP 처리기입니다. 처리기를 특정 유형의 리소스에 대한 태그를 만드는 방법을 알고 있는 특수한 렌더러로 생각하면 이해가 빠를 것입니다.
참고 실제적인 몇 가지 처리기 응용 프로그램을 비롯하여 HTTP 처리기에 대한 자세한 내용은 Serving Dynamic Content with HTTP Handlers 를 참조하십시오.
HTTP 모듈은 요청이 서버에서 해당 수명 주기의 단계를 통과하는 동안에 발생한 다양한 이벤트를 사용할 수 있는 클래스입니다. ASP.NET 응용 프로그램 이벤트와 같은 이벤트는 ELMAH 이벤트가 관심을 가지는 처리되지 않은 예외가 발생했을 때 발생하는 Error
이벤트입니다.
참고 HTTP 모듈을 사용하여 URL 재작성을 구현하는 방법을 비롯하여 HTTP 모듈에 대한 자세한 내용은 URL Rewriting in ASP.NET 을 참조하십시오.
그림 4는 ASP.NET HTTP 파이프라인을 그래픽으로 표현한 것입니다. IIS에 도착하는 요청으로부터 프로세스가 시작된다는 점에 주의해야 합니다. 요청된 리소스가 ASP.NET ISAPI 확장에 의해 처리되도록 구성되었다고 가정하면 IIS는 요청을 관리되지 않는 aspnet_isapi.dll
ISAPI 확장으로 디스패치합니다. 이 ISAPI 확장은 요청을 관리되는 ASP.NET 엔진에 전달합니다. 요청 수명 주기 동안에 하나 이상의 HTTP 모듈이 실행될 수 있습니다(등록된 모듈과 이러한 모듈이 구독한 이벤트에 따라 달라짐). 마지막으로 ASP.NET 엔진은 콘텐츠 렌더링, 처리기 호출 및 생성된 콘텐츠를 IIS로 반환하는 작업을 수행하는 HTTP 처리기를 결정합니다(IIS는 해당 콘텐츠를 다시 요청 클라이언트에게 반환함).
그림 4. 오류 로거를 통과하는 데이터 흐름
ELMAH는 Error
이벤트에 대한 이벤트 처리기를 가진 HTTP 모듈을 통해 중앙화된 오류 로깅을 제공합니다. 이벤트가 발생하면 ELMAH는 예외 세부 정보를 기록합니다. 또한 ELMAH는 주로 HTML 및 RSS 태그를 생성하여 오류 로그의 정보를 표시하는 역할을 수행하는 HTTP 처리기를 사용합니다.
모듈 또는 처리기 어셈블리를 웹 응용 프로그램의 /bin
디렉터리에 복사하고 몇 줄의 구성을 Web.config
파일에 복사하는 방법을 통해 다양한 처리기나 모듈을 사용하도록 기존의 웹 응용 프로그램을 구성합니다.
웹 응용 프로그램에 대해 HTTP 모듈을 구성하려면 추가할 모듈의 유형을 지정하는 <httpModules> 섹션을 Web.config
파일에 포함시켜야 합니다.
<httpModules> <add name="ModuleName" type="ModuleType" /> </httpModules>
ModuleType은 모듈의 유형을 지정하는 문자열로서 어셈블리 이름이 뒤에 오는 정규화된 클래스 이름(Namespace.ClassName)입니다. 또한 type
특성에는 강력한 이름의 어셈블리에 필요한 공개 키 토큰과 함께 버전 지정 및 culture 정보가 포함될 수 있습니다. 다음 코드는 ELMAH의 오류 로깅 모듈을 ASP.NET 응용 프로그램에 포함하기 위해 사용해야 하는 실제 <httpModules>
설정을 보여 줍니다.
<httpModules>
<add name="ErrorLog" type="GotDotNet.Elmah.ErrorLogModule,
GotDotNet.Elmah, Version=1.0.5527.0,
Culture=neutral, PublicKeyToken=978d5e1bd64b33e5" />
</httpModules>
Web.config
파일에 <httpHandlers> 섹션을 추가하여 웹 응용 프로그램에서 HTTP 처리기를 사용할 수 있습니다. HTTP 처리기가 특정 유형 리소스의 콘텐츠를 렌더링하므로 <httpHandlers>
요소는 type
특성 외에 path
특성을 포함합니다. 이 특성은 이 HTTP 처리기에 매핑해야 하는 파일 경로나 확장을 나타냅니다. 또한 GET 또는 POST 요청에서와 같이 특정 유형의 HTTP 요청에 한하여 처리기를 사용하도록 제한할 수 있는 verb
특성이 있습니다. 다음 예제는 .ashx
확장명을 가진 파일에 대한 모든 요청에서 호출되는 HTTP 처리기를 만듭니다.
<httpHandlers>
<add verb="*" path="*.ashx" type="HandlerType" />
</ httpHandlers >
HTTP 처리기에 대한 type
특성은 HTTP 모듈과 동일한 구문 옵션을 사용하여 표현합니다. Web.config
의 이러한 설정은 machine.config 파일에 포함할 수도 있습니다. 이렇게 하면 서버의 모든 웹 응용 프로그램에 대해 처리기와 모듈이 활성화되는 효과가 있습니다. 다음 코드는 이 기사의 다운로드에 포함된 데모의 Web.config
파일에 있는 <httpHandlers>
요소를 보여 줍니다. ErrorLogPageFactory
클래스가 /elmah/default.aspx
에 대한 모든 들어오는 요청을 렌더링하도록 지정된다는 것에 주의해야 합니다.
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah/default.aspx"
type="GotDotNet.Elmah.ErrorLogPageFactory, GotDotNet.Elmah,
Version=1.0.5527.0, Culture=neutral, PublicKeyToken=978d5e1bd64b33e5" />
</httpHandlers>
위에서 볼 수 있듯이 HTTP 모듈과 처리기를 ASP.NET 웹 응용 프로그램에 추가하는 것은 매우 간단하기 때문에 불과 몇 초 만에 끝낼 수 있으며 ASP.NET 응용 프로그램을 재컴파일하거나 재배포하지 않아도 됩니다. 이는 HTTP 모듈과 처리기가 재사용을 위한 뛰어난 도구일 뿐만 아니라 관리가 용이한 느슨하게 결합된 조각으로 응용 프로그램을 구성 요소화할 수 있는 수단을 제공하기 때문입니다.
ELMAH의 아키텍처는 다음 세 개의 하위 시스템으로 구성됩니다.
오류 로깅 하위 시스템은 두 개의 작업, 즉 오류를 로그에 기록하는 작업과 로그에서 오류 정보를 검색하는 작업을 수행합니다. HTTP 모듈 하위 시스템은 ASP.NET 응용 프로그램에서 처리되지 않은 예외가 발생할 경우의 오류 기록을 수행합니다. HTTP 처리기 하위 시스템은 오류 로그를 태그로 렌더링하여 오류 로그뿐만 아니라 RSS 피드에 대한 웹 기반 인터페이스를 구성할 수 있는 수단을 제공합니다.
그림 5에 나온 것처럼 HTTP 모듈 및 처리기 하위 시스템 모두 오류 로깅 하위 시스템을 사용합니다. HTTP 모듈 하위 시스템은 예외 정보를 오류 로깅 하위 시스템으로 보내고 HTTP 처리기 하위 시스템은 오류 정보를 읽어 렌더링합니다.
그림 5. 오류 로깅 시스템의 올바른 위치
ELMAH의 아키텍처를 제대로 이해하기 위해 이러한 세 개의 하위 시스템을 좀더 자세히 살펴보도록 하겠습니다.
오류 로깅 하위 시스템은 오류를 로그에 기록할 뿐만 아니라 특정 오류 또는 오류의 하위 집합에 대한 세부 정보를 검색하는 기능을 제공합니다. 이 기능은 다음과 같은 여러 클래스를 통해 가능합니다.
ErrorLog
에 대한 특정 Error
인스턴스를 나타냅니다. ErrorLogEntry
는 본질적으로 Error
인스턴스가 시작된 ErrorLog
인스턴스와 함께 Error
인스턴스를 그룹화합니다. 이러한 세 가지 클래스에 대한 개요와 중앙화된 완벽한 예외 로깅 유틸리티를 제공하기 위해서 이러한 클래스가 HTTP 모듈 및 HTTP 처리기 하위 시스템과 함께 작동하는 방법에 대해 살펴보도록 하겠습니다.
특정 프로젝트 설정 또는 전략에 따라서 서로 다른 백업 저장소를 오류 로그에 사용할 수 있습니다. 예를 들어 프로덕션 서버에서는 예외를 Microsoft SQL Server에 기록하지만 개발 서버에서는 오류를 단순히 XML 파일 집합이나 Microsoft Access 데이터베이스에 저장하기를 원할 수 있습니다. 다른 백업 저장소를 사용하는 기능을 제공하기 위해 오류 로깅 하위 시스템은 추상 기본 클래스인 ErrorLog
를 제공합니다. 이 클래스는 모든 ELMAH 오류 로거가 구현해야 하는 기본 메서드를 정의합니다. 이러한 메서드는 다음과 같습니다.
Error
클래스는 처리되지 않은 예외에 대한 정보를 나타냅니다. 이 Error
클래스에 대해서는 좀더 자세하게 설명할 것입니다. 오류 정보를 기록하면서 Log()
메서드는 또한 고유 식별자를 오류에 할당해야 합니다. ELMAH는 다음과 같은 두 개의 ErrorLog
구현을 제공합니다.
System.Data.SqlClient
공급자를 사용하여 오류를 Microsoft SQL Server 2000 데이터베이스에 기록합니다. SqlErrorLog
는 SQL Server 2000의 XML 기능 중 일부를 활용하기 때문에 SQL Server 2000이 필요하지만 이는 변경이 가능한 구현 세부 정보입니다. 일부 줄의 텍스트를 ASP.NET 웹 응용 프로그램의 Web.config
파일에 추가하는 간단한 방법으로 이러한 예외 로거 중 하나를 사용할 수 있습니다. 오류 세부 정보를 SQL Server나 응용 프로그램 메모리가 아닌 다른 장소에 저장해야 할 경우에는 고유한 사용자 지정 로거를 만들 수 있습니다. ELMAH에 대한 오류 로거를 구현하려면 ErrorLog를 확장하는 클래스를 만들고 원하는 저장소에 대해 Log()
, GetError()
및 GetErrors()
의 구현을 제공해야 합니다.
ELMAH의 HTTP 모듈 및 처리기 하위 시스템이 지정된 ErrorLog
클래스(SqlErrorLog
, MemoryErrorLog
또는 고유한 사용자 지정 로그 클래스)와 직접 상호 작용한다는 것에 주의해야 합니다. HTTP 모듈은 Error
인스턴스를 만들어 ErrorLog
메서드의 Log()
메서드에 전달하는 방법으로 예외 정보를 기록합니다. HTTP 처리기는 특정 ErrorLogEntry
인스턴스나 ErrorLogEntry
인스턴스 집합을 반환하는 ErrorLog
의 GetError()
및 GetErrors()
메서드를 통해 하나 이상의 오류에 대한 세부 정보를 읽습니다.
ErrorLog
의 Log()
메서드에는 Error
유형의 입력 매개 변수가 필요합니다. Exception
클래스는 코드 스택에서 응용 프로그램 수명 주기 동안에 예외 정보를 전달하는 데 더 적합하기 때문에 .NET Framework에서 제공되는 Exception
클래스 대신에 사용자 지정 Error
클래스가 사용됩니다. 그러나 Exception
개체는 저장, 입력 및 이식성 문제로 인하여 예외 로그를 저장하기에는 이상적이지 않습니다. 물론 이진 serialization을 사용하여 Exception
인스턴스를 저장할 수 있지만 이 경우에는 사용 가능한 동일한 유형 및 어셈블리 집합을 사용하여 Exception
개체를 시스템에서 deserialize할 수 있어야 합니다. 로그와 로그의 내용은 이식 가능해야 하며 특정 런타임 또는 구성을 가진 시스템에서만 볼 수 있는 것이 아니어야 하므로 이러한 제한은 특히 관리 및 운영 측면에서 볼 때 받아들일 수 없습니다. 게다가 Exception
인스턴스는 웹 응용 프로그램에 대한 고유한 주변 정보(예: 현재 웹 요청의 ServerVariables 컬렉션에 대한 값)가 부족한 경우가 자주 있는데 이러한 정보 중에서 일부는 진단을 위해 반드시 필요한 것입니다. 따라서 한 마디로 말하자면, Error
클래스는 웹 응용 프로그램에서 발생한 예외에 대한 정보를 보유하면서 모든 예외 유형을 대체하는 역할을 수행합니다.
표 1에는 Error
속성의 전체 목록이 나와 있습니다.
속성 | 설명 |
---|---|
Exception | 이 오류가 나타내는 Exception 인스턴스입니다. 클래스의 인스턴스와 함께 유지되지 않는 런타임 전용 속성입니다. |
ApplicationName | 이 오류가 발생한 응용 프로그램의 이름입니다. |
HostName | 이 오류가 발생한 호스트 시스템의 이름입니다. 기본값은 Environment.MachineName 입니다. |
Type | 오류의 유형, 클래스 또는 범주입니다. 일반적으로 예외의 전체 유형 이름(어셈블리 자격 제외)입니다. |
Source | 오류의 소스입니다. 일반적으로 Exception 개체의 Message 속성과 동일합니다. |
Message | 오류를 설명하는 간단한 텍스트입니다. 일반적으로 Exception 개체의 Message 속성과 같습니다. |
Detail | 오류에 대한 자세한 텍스트(예: 전체 스택 추적)입니다. |
User | 오류 발생 시에 응용 프로그램에 로그인한 사용자입니다(예: Thread.CurrentPrincipal.Identity.Name에 의해 반환된 사용자). |
Time | 오류가 발생한 날짜와 시간입니다. 항상 현지 시간입니다. |
StatusCode | 오류의 결과로 응답 헤더에서 반환되는 상태 코드입니다. 예를 들어 FileNotFoundException의 경우 404입니다. 그러나 이 값은 ASP.NET 내에서 항상 정확하게 결정되지는 않습니다. 경우에 따라 이 StatusCode 값은 0으로 보고될 수 있습니다. |
WebHostHtmlMessage | 사용자 지정 오류 페이지가 없을 경우 웹 호스트(ASP.NET)가 생성한 기본 HTML 메시지입니다. |
ServerVariables | HttpRequest.ServerVariables에 포함되어 있는 것과 같은 웹 서버 변수의 NameValueCollection입니다. |
QueryString | HttpRequest.QueryString에 포함되어 있는 것과 같은 HTTP 쿼리 문자열 변수의 NameValueCollection 입니다. |
Form | HttpRequest.Form에 포함되어 있는 것과 같은 양식 변수의 NameValueCollection 입니다. |
Cookies | HttpRequest.Cookies에 포함되어 있는 것과 같은 클라이언트가 보낸 쿠키의 NameValueCollection 입니다. |
WebHostHtmlMessage
속성에 대해서는 약간의 설명이 필요합니다. ASP.NET 웹 응용 프로그램에서 처리되지 않은 예외가 발생했으며 응용 프로그램이 사용자 지정 오류 페이지를 사용하도록 구성되지 않은 경우 그림 6과 비슷한 화면이 표시됩니다. 이 화면은 모든 ASP.NET 개발자에게는 익숙한 화면입니다.
그림 6. 표준 오류 페이지
예외가 발생하면 해당 화면의 실제 HTML 태그가 액세스되어 Error
클래스의 WebHostHtmlMessage
속성에 저장됩니다. 특정 예외에 대한 세부 정보를 표시하는 페이지를 방문했을 때 해당 Error
인스턴스가 WebHostHtmlMessage
속성에 값을 갖고 있는 경우 그림 6과 유사한 실제 예외 정보 화면을 표시하는 페이지에 대한 링크가 방문자에게 제공됩니다. 여기에서는 기록된 예외를 확인할 수 있을 뿐만 아니라 나중에 로그 검사 시에 ASP.NET에 의해 생성된 원래 오류 페이지를 방문할 수 있습니다. 또한 이와 함께 사용자 지정 오류도 활성화되어 있습니다.
Error
클래스는 또한 XML 형식과의 사이에서 해당 상태를 serialize 및 deserialize할 수 있는 방법을 제공합니다. 자세한 내용은 함께 제공되는 코드에서 FromXml
및 ToXml
을 참조하십시오.
오류 로깅 하위 시스템의 마지막 클래스는 Error
인스턴스를 ErrorLog
인스턴스와 연결하는 ErrorLogEntry
클래스입니다. HTTP 처리기 하위 시스템이 특정 예외에 대한 정보를 검색하기 위해 GetError()
메서드를 호출하면 GetError()
메서드는 특정 백업 저장소에서 정보를 검색하여 ErrorLogEntry
인스턴스에서 해당 정보를 채웁니다. ErrorLogEntry
클래스에는 다음 세 개의 속성이 포함되어 있습니다.
ErrorLog
인스턴스에 대한 참조입니다. Error
클래스의 인스턴스입니다. GetError()
메서드가 단일 ErrorLogEntry
인스턴스를 반환하는 것과 달리 GetErrors()
는 ErrorLogEntry
인스턴스의 목록을 반환합니다. GetErrors()
는 특히 한 번에 n개의 레코드씩 오류를 페이징할 수 있도록 설계되었습니다.
그림 7은 업데이트된 ELMAH의 아키텍처를 보여 주며, 오류 로깅 하위 시스템이 더 자세히 나와 있습니다.
그림 7. 업데이트된 아키텍처
ELMAH는 두 개의 HTTP 모듈, 즉 ErrorLogModule
및 ErrorMailModule
로 구성됩니다. ErrorLogModule
은 응용 프로그램의 Error
이벤트에 대한 이벤트 처리기를 만드는 HTTP 모듈입니다. 처리되는 않은 예외가 발생할 경우 이 HTTP 모듈은 응용 프로그램의 구성에 지정된 대로 적절한 오류 로거를 가져와 Log()
메서드를 호출함으로써 현재 요청에 대한 HttpContext와 예외 정보로 채워진 Error
인스턴스를 전달합니다. 다음 소스 코드는 ErrorLogModule
클래스의 관련 코드를 보여 줍니다.
public class ErrorLogModule : IHttpModule
{
public virtual void Init(HttpApplication application)
{
application.Error += new EventHandler(OnError);
}
protected virtual ErrorLog ErrorLog
{
get { return ErrorLog.Default; }
}
protected virtual void OnError(object sender, EventArgs args)
{
HttpApplication application = (HttpApplication) sender;
LogException(application.Server.GetLastError(), application.Context);
}
protected virtual void LogException(Exception e, HttpContext context)
{
try
{ this.ErrorLog.Log(new Error(e, context)); }
catch (Exception localException)
{ Trace.WriteLine(localException); }
}
}
ErrorLogModule
의 실행은 Init()
메서드에서 시작되는데, 이 메서드는 Error
이벤트가 발생할 때마다 OnError()
메서드를 호출해야 함을 ASP.NET 런타임에 표시합니다. OnError()
메서드는 HttpApplication
개체를 참조하며 LogException()
메서드를 호출하여 마지막 예외에 대한 세부 정보뿐만 아니라 특정 요청과 관련된 HttpContext
인스턴스를 전달합니다. LogException()
은 간단하게 해당 ErrorLog
클래스의 Log()
메서드를 호출하여 새 Error
인스턴스를 전달합니다. Error
인스턴스의 생성자는 Exception
및 HttpContext
인스턴스를 가지며 이에 따라서 속성을 채웁니다. 자세한 내용은 다운로드할 수 있는 소스 코드를 참조하십시오.
ErrorLogModule
은 읽기 전용 ErrorLog
속성을 포함하며 ErrorLog.Default
에 의해 반환된 ErrorLog
인스턴스를 반환합니다. Default
는 ErrorLog
클래스에 있는 ErrorLog
유형의 정적 속성입니다. 이 속성은 웹 응용 프로그램의 구성을 참조하여 예외 로깅에 사용할 클래스(SqlErrorLog
, MemoryErrorLog
또는 사용자 지정 예외 로깅 클래스)를 결정합니다.
참고 ASP.NET 웹 응용 프로그램에 ELMAH 추가 절에서는 특정 예외 로거를 사용하도록 웹 응용 프로그램을 구성하는 방법을 검토합니다. 이 작업은 줄의 일부를Web.config
또는machine.config
파일에 추가하기만 하면 되므로 아주 간단합니다.
HTTP 모듈 하위 시스템의 다른 HTTP 모듈은 예외 발생 시에 관리자에게 전자 메일을 보내는 ErrorMailModule
클래스입니다. ELMAH의 이 모듈에 대해서는 여기에서 언급하지 않겠지만 이 기사에서 다운로드할 수 있는 코드 샘플에서 이 모듈을 사용하는 방법을 확인할 수 있습니다.
앞에서 언급한 것처럼 HTTP 처리기의 목적은 특정 리소스 유형의 콘텐츠를 렌더링하는 것입니다. ASP.NET HTTP 파이프라인에 요청이 들어오면 ASP.NET 엔진은 요청된 경로를 검토하여 요청된 리소스를 처리하는 데 사용해야 할 HTTP 처리기를 결정합니다. 특히 HTTP 처리기나 HTTP 처리기 팩토리에 의해 처리되는 특정 경로를 가지도록 ASP.NET 응용 프로그램을 구성할 수 있습니다. HTTP 처리기 팩토리는 콘텐츠 렌더링을 직접적으로 수행하는 것이 아니라 HTTP 처리기 인스턴스의 선택과 반환을 담당하는 클래스입니다. 요청된 리소스를 렌더링하는 작업은 반환된 이 HTTP 처리기 인스턴스가 수행합니다.
ELMAH의 HTTP 처리기 하위 시스템은 단일 HTTP 처리기 팩토리 클래스와 함께 기록된 오류를 표시하기 위해 태그를 생성하도록 설계된 여러 HTTP 처리기 클래스로 구성됩니다. HTTP 처리기 팩토리 클래스인 ErrorLogPageFactory
는 요청된 URL의 PathInfo
부분을 검사하여 출력을 생성해야 하는 HTTP 처리기를 결정합니다.
참고 URL의PathInfo
부분은 파일 이름 뒤에 오는 추가 콘텐츠이며Request
개체의 PathInfo 속성을 통해 사용할 수 있습니다. 예를 들어http://www.example.com/someDir/somePage.aspx/somePath
URL에서 somePath는 URL의PathInfo
부분입니다. URL의 다양한 부분에 사용되는 용어와 해당Request
개체 속성에 대한 자세한 내용은 Rick Strahl 의 블로그 항목 Making Sense of ASP.NET Paths 를 참조하십시오.
다음 코드는 ErrorLogPageFactory
HTTP 처리기 팩토리 클래스에 있는 더 흥미로운 코드를 보여 줍니다.
public class ErrorLogPageFactory : IHttpHandlerFactory
{
public virtual IHttpHandler
GetHandler(HttpContext context,
string requestType, string url, string pathTranslated)
{
string resource =
context.Request.PathInfo.Length == 0 ? string.Empty
: context.Request.PathInfo.Substring(1);
switch (resource.ToLower(CultureInfo.InvariantCulture))
{
case "detail" : return new ErrorDetailPage();
case "html" : return new ErrorHtmlPage();
case "rss" : return new ErrorRssHandler();
default : return new ErrorLogPage();
}
}
}
위에서 알 수 있듯이 ErrorLogPageFactory
클래스의 GetHandler()
메서드는 요청의 PathInfo
에 기초하여 HTTP 처리기 인스턴스를 반환합니다. PathInfo
가 rss
인 경우 ErrorRssHandler
HTTP 처리기의 인스턴스가 반환되며 이 인스턴스는 로그를 RSS 필드로 렌더링합니다. PathInfo
가 detail
인 경우 ErrorDetailPage
HTTP 처리기의 인스턴스가 반환되며 이 인스턴스는 특정 예외에 대한 정보를 표시합니다.
ASP.NET 웹 응용 프로그램의 설정에서 ErrorLogPageFactory
HTTP 처리기 팩토리에 매핑할 경로를 지정해야 합니다(예: ErrorLog.aspx
). 예외 로그의 RSS 피드를 보려면 http://www.example.com/ErrorLog.aspx/rss
를 방문하십시오.
ELMAH의 다양한 HTTP 처리기 클래스(ErrorDetailPage
, ErrorHtmlPage
, ErrorRssHandler
, ErrorLogPage
등)는 다른 태그를 렌더링합니다. 예를 들어 ErrorRssHandler
HTTP 처리기는 15개의 최신 오류를 반복하여 이 정보를 RSS 형식으로 표시하기 위한 적절한 XML 태그를 내보냅니다. 다른 모든 HTTP 처리기는 모든 ASP.NET 코드 숨김 클래스가 파생되는 System.Web.UI.Page
클래스에서 직접 또는 간접적으로 파생됩니다. 이러한 페이지 관련 HTTP 처리기는 기록된 예외의 페이징 가능한 목록을 표시하는 HTML 인터페이스를 만들기 위해 Page
클래스의 Render() 및 OnLoad() 메서드를 무시합니다. 이러한 페이지의 스크린샷인 그림 1, 2 및 3을 다시 참조하십시오.
참고Error
클래스가ServerVariables
,QueryString
,Form
및Cookie
컬렉션을 저장하지만ServerVariables
컬렉션만 예외의 세부 정보에 표시됩니다. 이는QueryString
매개 변수와 쿠키를 각각ServerVariable
의QUERY_STRING
및HTTP_COOKIE
매개 변수를 통해 볼 수 있기 때문입니다.Form
컬렉션은 생략되는데, 이는 대부분의 진단에서 거의 도움이 되지 않는 수십 KB의 뷰 상태 정보가 잠재적으로 이 컬렉션에 포함될 수 있기 때문입니다. 물론 원할 경우에는 HTTP 처리기 세부 정보를 간단하게 수정하여 이 정보를 포함할 수 있습니다.
이제 ELMAH의 세 가지 하위 시스템을 검토했으므로 ELMAH를 기존 ASP.NET 웹 응용 프로그램에 추가하는 방법을 살펴보겠습니다. 특히 ELMAH는 HTTP 처리기와 모듈이 제공하는 구성 요소화의 이점으로 인해 임의의 사이트에 매우 간단하게 추가할 수 있습니다.
ELMAH를 ASP.NET 웹 응용 프로그램에 추가하는 것은 매우 간단하며 다음 두 단계로 구성됩니다.
어셈블리를 웹 응용 프로그램의 /bin
디렉터리에 복사하고 Web.config
파일을 통해 ELMAH의 설정을 구성하여 ELMAH를 웹 서버의 특정 웹 응용 프로그램에 적
VISUAL STUDIO Theme Gallery (0) | 2008.03.20 |
---|---|
[펌] 리플렉션을 사용하여 비즈니스 개체를 ASP.NET 폼 컨트롤에 바인딩 (0) | 2006.02.01 |
[펌] Smart Client를 이용한 파일 업로드 (0) | 2006.01.18 |
ASP.NET 에서 EventLog 이용할 경우 어드민 권한으로 가장하기.. (0) | 2006.01.17 |
[펌]Quick and Dirty Guide to Configuring Log4Net For Web Applications (0) | 2006.01.09 |
스탈린의 일대기는 멜로디를 중시하는 소비에트식의 악곡으로 인해 오랫동안 사랑받아왔다. 그 '전설'은 영웅적인 우드스탁 혁명의 모의자이자 전설적인 기타리스트인 레닌의 충실한 추종자로서 그의 위대성을 입증받고 있다. 히틀러는 예술적 감각이 뛰어나 게르만민족의 순수 락을 연주하여 게르만인의 우수성을 입증했다. 그리고 같은 동맹국인 무솔리니도 합류하였다.
|
본조비-It's my life..!(이경원연주) (0) | 2006.05.15 |
---|---|
[본문 스크랩] Far Beyond the Sun (MV) - Yngwie Malmsteen (0) | 2006.02.16 |
[펌] Stryper - In God We Trust (0) | 2006.01.24 |
[펌] 슈퍼마리오 아카펠라Ver. (0) | 2005.09.14 |
[펌] Incubus - Drive (0) | 2005.08.31 |
Firebug !!! (0) | 2006.12.21 |
---|---|
이미지 없이 둥근 모서리 박스 만드는 소스 (0) | 2006.11.02 |
드뎌 나왔군... Ajax in action (0) | 2005.10.17 |
[펌] 동적 테이블 생성 샘플 DHTML (0) | 2005.09.06 |
[js] 설명 정리 끝짱이다.. 강추 링크... (2) | 2005.08.26 |
[방문히트이벤트] 20000 히트를 잡아라! (이웃한정) 박종복님이 당첨되었습니다. |
오늘 주문한 책. (0) | 2006.02.02 |
---|---|
자동차 오토미션 전문수리점 (0) | 2006.02.01 |
[펌] MS 인터넷 익스플로러(IE)의 ActiveX 작동변경 내용 (0) | 2006.01.25 |
지금 읽고 있는 책, 시킨 책.. (0) | 2006.01.12 |
생일축하 이벤트!!! (4) | 2006.01.11 |
MS 인터넷 익스플로러(IE)의 ActiveX 작동변경 내용
2006-01-23
Microsoft .NET MVP
삼성SDS 강상진
아래 내용은 2006년 1월 현재, 웹기반 어플리케이션을 개발하시거나,
기존의 웹 사이트를 유지보수 하시는 분들에게 해당하는 내용 입니다.
자세한 내용은 한국MS에서 제공한 첨부파일을 확인하시기 바랍니다.
간략하게 말씀드리면 2006년 2월부터 인터넷 익스플로러에 ActiveX활성화를 금지하는
패치가 추가 됩니다. 이 패치는 모든 웹사이트에 대하여 기존 ActiveX 개체를 비활성화 시킵니다.
이러한 쌩뚱맞은 정책의 배경은 다음과 같습니다.
- 발생배경 -
1. 인터넷 브라우져(IE, FireFox, Netscape, Opera 등) 에 또 다른 컴포넌트(대표적으로 ActiveX)를
삽입하는 기술에 대한 특허를 보유한 벤쳐기업인 이올라스(Eolas Technologies)社 에서
Microsoft를 상대로 IE가 ActiveX를 사용하는것에 대한 특허침해 부분을 미법원에 고소.
2. 미법원, Eolas사의 주장 인정하여, Microsoft 패소 (현재 항소 진행중)
3. Microsoft, 2006년 2월부터 ActiveX의 활성화를 차단하는 윈도우즈 패치 배포예정
4. Microsoft, 2006년 2월 15일, Windows Update에 '권장항목' 으로 등록 예정
5. Microsoft, 2006년 4월 12일, IE의 누적패치에 관련 패치 포함 예정
: 다른 보안 패치들과 함께 알게 모르게 자동배포된다고 보시면 됩니다.
6. MS에 대한 판결이 완료되면, 다른 브라우져에 대한 고소또한 진행될듯 합니다.
7. MS사가 특허료를 지불하고 계속 현재 내용을 유지하는것으로 합의가 될수도 있었으나,
이는 특허내용과 패소를 인정하는것이기에 하지 않는다고 합니다.
- 예상결과 -
1. HTML문서의 <Applet> , <Embed> , <Object> 태그로 삽입한 ActiveX 컨트롤과
즉시 상호작용 불가능 : 해당 개체의 UI를 클릭하여, 먼저 활성화해야 상호작용 가능
2. 비활성화 되는 ActiveX의 종류
Windows Media Player(동영상, 음악 삽입시) , Flash, VB나 C++로 자체 제작한 컴포넌트 등
3. 국내 사이트중, 금융뱅킹이나, 플래시로 제작한 서브메뉴 트리등이 타격이 심할것으로 예상
- 대비책 -
1. 원하지 않는 내용의 패치는 받지 않을수 있음. (근시안적 대책)
2. HTML로 삽입한 개체를 JavaScript로 작성하여 외부JS파일로 등록후 사용
: 첨부파일에 자세히 설명 되어 있음
- 추가내용 -
1. 확인결과, 플래시나, 윈도우즈 미디어 플레이어는 자동으로 Play는 됩니다.
(예 : 싸이월드,네이버 블로그의 배경음악등은 기존과 동일, PAUSE나 STOP을 위해서는
클릭이나 엔터를 사용하여 활성화 후에 가능)
2. 은행 사이트의 공인인증서는 기존과 동일하게 사용가능
3. 현재 패치의 Pre-DownLoad가 가능하니(MSDN Subscribers 사이트), 웹개발자들은
미리 각자의 웹사이트 소스수정을 하여 테스트 하는것이 가능 합니다.
4. 모든 IE 버젼에 동일하게 적용됩니다.
5. 2006년말 출시예정인 Windows VIsta에 포함된 IE7버젼에는 미리 적용되어 출시 됩니다.
6. UI를 가지고 있지 않는 ActiveX개체는 여기에 포함되지 않습니다.
한 가지 더 제 생각을 말씀 드리자면,
자동으로 페이지의 모든 ActiveX개체를 한번씩 클릭해주는 효과를
발생하는 스크립트나 윈도우즈 어플리케이션등..
꽁수(?)가 곧 생겨나지 않을까 생각 합니다..
하지만 이 방법이 특허내용을 마찬가지로 침해한다면 배포가 불가능할것 입니다.
- 참고 사이트 -
1. IE, ActiveX 동작법 변경에 따른 파급 효과
http://channy.creation.net/blog/?p=213
2. IE, ActiveX 동작법 변경에 따른 파급 효과'를 읽고
http://blog.naver.com/saltynut/120020428904
3. Eolas와의 특허소송과 관련한 Microsoft의 입장
http://www.microsoft.com/korea/windows/ie/activex/default.mspx
4. ActiveX 컨트롤 활성화
http://www.microsoft.com/korea/windows/ie/activex/activate/default.mspx
5. 일반적 사항에 대한 FAQ
http://www.microsoft.com/korea/windows/ie/activex/faq/default.mspx
6. 기술적 사항에 대한 FAQ
http://www.microsoft.com/korea/windows/ie/activex/technical/faq/default.mspx
7. Activating ActiveX Controls
http://msdn.microsoft.com/library/?url=/workshop/author/dhtml/overview/activating_activex.asp
8. 이올라스가 보유한 특허의 내용
9. 이올라스가 보유한 특허에 대한 W3C 의장 팀 버너스 리의 입장
http://www.theregister.co.uk/2003/10/30/bernerslee_comes_out_fighting/
10. 이올라스가 보유한 특허에 대한 W3C의 입장
http://www.w3.org/2003/10/28-906-briefing.html.en
자동차 오토미션 전문수리점 (0) | 2006.02.01 |
---|---|
20000 히트 이벤트!!! (2) | 2006.01.26 |
지금 읽고 있는 책, 시킨 책.. (0) | 2006.01.12 |
생일축하 이벤트!!! (4) | 2006.01.11 |
[지식인에서 펌] 감성돔 채비. (0) | 2006.01.09 |
[본문 스크랩] Far Beyond the Sun (MV) - Yngwie Malmsteen (0) | 2006.02.16 |
---|---|
[펌] 락이 세상을 구원한다. (0) | 2006.01.27 |
[펌] 슈퍼마리오 아카펠라Ver. (0) | 2005.09.14 |
[펌] Incubus - Drive (0) | 2005.08.31 |
[펌] Mind Revolution - Skyfire (0) | 2005.08.22 |
1) 파일 업로드
1. 다중 파일 다운로드 가능
2. 이어받기 가능
3. Context 메뉴
2) 파일 다운로드
1. 다중 파일 업로드 가능
2. 윈도우 탐색기에서 Drag & Drop 가능 (파일, 폴더를 한꺼번에 지정해도 됩니다)
그리고 파일 사이즈가 0인 것 추가하지 않습니다
3. 다운로드 하고 싶은 위치 지정(폴더 생성)
-- 기본적으로 c:\download 라는 곳에 저장하게 되어 있고 폴더가 생성되어 있지 않으면
폴더를 자동적으로 생성합니다.
4. Context 메뉴
아 그리고 진행상황을 알 수 있는 Progress bar를 추가시켰습니다
(이 부분은 다른 분이 해놓은게 있어서 약간 수정해서 사용했습니다. 참고한 분의 이름은 잘 기억이....)
##################
궁금하지 않지만 한번 실행해보시고자 하시는 분은
앞에서 설명들렸듯이 .Net 권한설정을 해야합니다
권한 설정하는 파일은 첨부파일로 같이 올립니다
SmartClientSet.xml과
Smart-2422.bat (파일명이 지 맘대로 바뀌네요)
xml파일은 해당 dll의 권한 설정파일이고
bat 파일은 해당 dll의 권한을 여러분의 pc에서 사용할 수 있게 권한추가하는 bat 파일입니다
bat 파일내용..
(만약 .net Frame work이 다른곳에 깔려 있다면 해당 위치를 정확하게 적어주셔야 겠죠
그것도 귀찮으시다면 .Net 명령 프롬프트에서 사용하시면 됩니다.)
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\caspol -machine -addpset SmartClientSet.xml
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\caspol -machine -addgroup Internet_Zone -url http://www.wunge.com/* SmartClientSet -n InternetSmartClient_Zone
테스트 후 삭제는 태요사이트의 정성태님의 강좌를 보시면 삭제하실 수 있을겁니다
##########################################
위의 설정을 다 하셨다면
다운로드
http://www.wunge.com/pino93/download.aspx
업로드
http://www.wunge.com/pino93/fileupload.aspx
##########################################
참고로 후배의 도메인을 빌려서 사용하기 때문에 대용량의 30M 이상의 파일은 업로드 제한을 걸어놨으며 편의상 확인하기 쉽게 업로드와 다운로드 폴더를 하나로 지정했습니다
업로드 후 다운로드 창을 리로드하면 업로드한 파일이 보일 겁니다...
안보이면.. 말고~~
전체적인 용량은 제한을 두지 않았으니 많은 파일을 올리지는 마세요..
후배 계정 사라집니다. ㅡ.ㅡ;;;
그리고 소스파일은 WebApp.zip 파일인데
혹 개인 PC에서 설정해서 사용하시려면 몇가지 수정해야 할 사항이 있습니다
일반적인 Web상에서의 파일 업로드는 Post방식을 사용하지만
.Net에서 제공하는 WebClient의 PUT방식을 (물론 WebClient에서는 Post방식도 지원함) 사용하였기에 IIS 부분의 설정부분을 변경해야 되며
Source 부분에서 파일을 업로드할 계정과 암호 부분을 수정해야하며
업로드할 폴더를 웹공유부분에서 쓰기권한이 있어야 합니다.
1) PUT방식을 사용하기 위한 수정방법은
IIS 환경설정부분에서 해당 가상 디렉터리의 속성(마우스 오른쪽 버튼을 누르면 있습니다)을 선택하신 후 디렉터리라는 탭을 선택하시고 아래부분의 구성을 누르시면 응용 프로그램 구성이 나옵니다
매핑탭을 선택 한 후 확장명이 .cs가 있는지 확인 하시고 만약 없다면 새로 생성해주시구요
아래 이미지같이 추가해 주시면 됩니다. 일반적으로 PUT이라는 게 없죠..
그리고 혹시나 각 .NetFrameWork 버젼마다 aspnet_isapi.dll 파일 위치가 다르니 확인하세요
서버군은 C:\WINDOWS가 아닌 C:\WINNT~ 이렇게 되겠죠 ^^
(원래 말로 설명하려 했는데 설명이 조잡해서 이미지 캡쳐 떴습니다)
2. 파일쓰기 권한은
아래 이미지의 중간부분에 쓰기(W)를 체크해주시면 되는데 여기서 해당파일을 업로드 할 폴더를 선택하신 후 속성에서 쓰기 권한을 주세요
그렇지 않으면 다른 폴더까지 권한이 주어지니까요..
아래 이미지는 가로 사이즈가 550을 넘어서 깨지니 클릭을 하신 후 큰 화면으로 보세요~~~
[펌] 리플렉션을 사용하여 비즈니스 개체를 ASP.NET 폼 컨트롤에 바인딩 (0) | 2006.02.01 |
---|---|
[펌] HTTP 모듈과 처리기를 사용하여 플러그형 ASP.NET 구성 요소 만.. (0) | 2006.02.01 |
ASP.NET 에서 EventLog 이용할 경우 어드민 권한으로 가장하기.. (0) | 2006.01.17 |
[펌]Quick and Dirty Guide to Configuring Log4Net For Web Applications (0) | 2006.01.09 |
http://www.devintelligence.com/Log4NetViewer/ (0) | 2006.01.09 |
Stephen Walther
Superexpert
2004년 8월
적용 대상:
Microsoft ASP.NET 2.0
요약: 마스터 페이지에서는 일관된 주제와 스타일을 따르는 ASP.NET 페이지를 만들 수 있습니다. Stephen Walther기 이 새로운 기능을 활용하는 방법을 설명합니다(27페이지/인쇄 페이지 기준).
소개
마스터 페이지 및 콘텐츠 페이지
간단한 마스터 페이지 만들기
간단한 콘텐츠 페이지 만들기
사이트 탐색 기능이 있는 마스터 페이지 만들기
여러 마스터 페이지 중첩
마스터 페이지 구성
마스터 페이지 속성 재정의
페이지 제목 특성 사용
HTML 헤더 특성 재정의
마스터 페이지에서 속성 및 메서드 제공
동적으로 마스터 페이지 로드
결론
관련 서적
Microsoft ASP.NET 2.0의 새 기능인 마스터 페이지를 사용하면 웹 응용 프로그램에서 같은 페이지 레이아웃을 여러 콘텐츠 페이지에 적용할 수 있습니다. 또한 일관성 있는 모양과 느낌의 웹 사이트를 만드는 것이 쉬워집니다(이 기사에는 영문 페이지 링크가 포함되어 있습니다).
대부분의 웹 응용 프로그램 페이지에는 로고, 탐색 메뉴, 저작권 표시 등의 표준 요소가 있습니다. 이러한 모든 요소를 단일 마스터 페이지에 배치할 수 있습니다. 이 마스터 페이지를 기반으로 하여 응용 프로그램 콘텐츠 페이지를 만들면 모든 콘텐츠 페이지에 동일한 표준 요소가 자동으로 포함됩니다.
이 기사에서는 마스터 페이지를 활용하여 표준 페이지 레이아웃을 만드는 방법을 알아봅니다. 또한 마스터 페이지의 몇 가지 고급 기능에 대해서도 살펴봅니다. 예를 들어 콘텐츠 페이지에서 페이지 제목 및 메타 태그와 같은 헤더 속성을 수정하는 방법을 설명하고, 실행 중에 여러 마스터 페이지를 동적으로 로드하는 방법도 설명합니다.
먼저, 간단한 마스터 페이지를 만들어 보겠습니다. 메모장을 사용하여 마스터 페이지를 만들 수도 있고 Microsoft Visual Web Developer의 디자이너 지원 기능을 활용하여 마스터 페이지를 만들 수도 있습니다(그림 1 참조). Visual Web Developer를 사용하여 마스터 페이지를 만드는 것이 더 재미있지만, 이 기사에서는 Visual Web Developer를 사용하지 않습니다.
그림 1. 마스터 페이지에 대한 디자이너 지원
일반 ASP.NET 페이지를 만드는 것과 같은 방법으로 마스터 페이지를 만듭니다. 마스터 페이지에는 표준 ASP.NET 페이지에 추가하는 것과 동일한 Web 컨트롤, User 컨트롤, HTML 콘텐츠 및 스크립트를 포함할 수 있습니다. 그러나 마스터 페이지와 일반 ASP.NET 페이지 간에는 세 가지의 중요한 차이점이 있습니다.
첫째로, 일반 ASP.NET 페이지와 달리 마스터 페이지의 이름은 특수한 확장명인 .master로 끝나야 합니다. 이 확장명은 해당 페이지가 마스터 페이지임을 나타냅니다. 또한 ASP.NET 응용 프로그램은 확장명이 .master인 페이지를 요청할 수 없도록 구성되므로 마스터 페이지를 직접 요청할 수 없습니다. 대신, 마스터 페이지를 기반으로 하는 콘텐츠 페이지를 요청합니다.
둘째로, 마스터 페이지에는 일반 <%@ Page %> 지시문 대신 <%@ Master %> 지시문이 포함됩니다. <%@ Master %> 지시문은 <%@ Page %> 지시문과 동일한 특성을 대부분 지원합니다. 예를 들어 <%@ Master Language="vb" %> 지시문을 사용하여 페이지의 프로그래밍 언어를 지정할 수 있습니다.
마스터 페이지와 일반 ASP.NET 페이지 간의 세 번째 차이점은 마스터 페이지에 ContentPlaceHolder 컨트롤을 포함하지 않을 수도 있고 여러 개 포함할 수도 있다는 점입니다. 마스터 페이지에서만 ContentPlaceHolder 컨트롤을 사용할 수 있습니다. 이 컨트롤은 특정 콘텐츠 페이지에서 재지정할 수 있는 마스터 페이지의 영역을 표시합니다.
목록 1의 마스터 페이지 Simple.master에는 두 개의 ContentPlaceHolder 컨트롤이 있는 HTML 테이블이 포함되어 있습니다.
목록 1. Simple.master
<%@ Master %><html><head> <title>Simple Master Page</title></head><body><form id="form1" runat="server"><table width="100%"><tr> <td> <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server" /> </td> <td> <asp:ContentPlaceHolder id="ContentPlaceHolder2" runat="server" /> </td></tr></table></form></body></html>
목록 1의 마스터 페이지에는 ContentPlaceHolder1 및 ContentPlaceHolder2의 두 ContentPlaceHolder 컨트롤이 있습니다. 이 두 컨트롤은 특정 콘텐츠 페이지의 경우에 수정할 수 있는 마스터 페이지의 영역을 표시합니다. Visual Web Developer 디자이너에서 목록 1의 마스터 페이지를 열면 그림 2의 페이지가 나타납니다.
그림 2. Simple.master 마스터 페이지
목록 1의 마스터 페이지에는 표준 HTML 여는 태그가 포함되어 있습니다. 예를 들어 여기에는 HTML <title> 및 <body> 태그가 있습니다. 일반적으로 이러한 표준 태그를 마스터 페이지에 포함합니다. 이 기사의 뒷부분에 있는 "마스터 페이지 속성 재정의" 섹션에서 특정 콘텐츠 페이지의 제목을 변경하는 방법을 설명하겠습니다.
마스터 페이지에는 서버 쪽 <form> 태그도 포함되어 있습니다. ASP.NET 페이지에서는 서버 쪽 <form> 태그를 하나만 사용할 수 있으므로, 대부분의 경우 이 태그를 마스터 페이지에 포함합니다.
마스터 페이지를 만든 후에는 이 마스터 페이지를 기반으로 하나 이상의 콘텐츠 페이지를 만들 수 있습니다. 콘텐츠 페이지는 웹 브라우저에서 요청하는 실제 페이지입니다. 콘텐츠 페이지의 확장명은 일반 ASP.NET 파일과 같은 .aspx입니다. 다음의 두 가지 주요 예외를 제외하면 콘텐츠 페이지는 일반 ASP.NET와 유사합니다.
첫째로, 콘텐츠 페이지의 모든 콘텐츠는 Content 컨트롤에 포함해야 합니다. Content 컨트롤은 콘텐츠 페이지의 콘텐츠 영역을 마스터 페이지에서 ContentPlaceHolder 컨트롤이 표시한 콘텐츠 영역에 매핑하는 데 사용됩니다.
둘째로, 콘텐츠 페이지를 마스터 페이지에 연결해야 합니다. <%@ Page %> 지시문의 특성을 사용하여 콘텐츠 페이지를 마스터 페이지에 연결할 수 있습니다. 웹 구성 파일을 사용하여 여러 콘텐츠 페이지를 마스터 페이지에 연결할 수도 있습니다.
예를 들어 목록 2의 콘텐츠 페이지에 있는 두 개의 Content 컨트롤은 목록 1의 마스터 페이지에 있는 ContentPlaceHolder 컨트롤에 해당합니다.
목록 2. Simple.aspx
<%@ Page MasterPageFile="~/Simple.master" %><asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="server"> Content in Left Column</asp:Content><asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="server"> Content in Right Column</asp:Content>
목록 2에 있는 콘텐츠 페이지의 <%@ Page %> 지시문에는 MasterPageFile 특성이 포함되어 있습니다. 이 특성은 콘텐츠 페이지를 목록 1의 마스터 페이지에 연결합니다.
두 Content 컨트롤에는 모두 여는 태그와 닫는 태그 사이에 텍스트가 있습니다. 이러한 경우 Content 컨트롤에는 단순히 텍스트만 포함됩니다. 그러나 Web 컨트롤 및 User 컨트롤을 비롯하여 Content 컨트롤 내에 원하는 콘텐츠를 얼마든지 추가할 수 있습니다.
Visual Web Developer에서 콘텐츠 페이지를 편집하면 다른 작업 중에 마스터 페이지가 복제됩니다(그림 3 참조). Visual Web Developer는 마스터 페이지에서 각 ContentPlaceHolder에 해당하는 Content 컨트롤을 자동으로 추가합니다.
그림 3. Visual Web Developer에서 콘텐츠 페이지 편집
이전 섹션에서 설명한 마스터 페이지와 콘텐츠 페이지는 매우 단순합니다. 실제로는 메뉴 모음이나 사이트 이동 경로(bread crumb trail)와 같은 표준 탐색 요소를 마스터 페이지에 추가할 수 있습니다. 이 섹션에서는 보다 많은 내용이 들어 있는 마스터 페이지를 만드는 과정을 살펴봅니다(그림 4 참조).
그림 4. 보다 복잡한 마스터 페이지
이 마스터 페이지에는 SiteMapPath 컨트롤 및 탐색용 Menu 컨트롤이 포함됩니다. SiteMapPath 컨트롤은 사이트 이동 경로(bread crumb trail)를 표시하고 Menu 컨트롤은 탐색 메뉴를 표시합니다. 두 컨트롤 모두 목록 3의 SiteMap 파일을 사용합니다.
목록 3. web.sitemap
<?xml version="1.0" encoding="utf-8"?><siteMap> <siteMapNode url="~/Default.aspx" title="Home"> <siteMapNode url="~/Products.aspx" title="Products"/> <siteMapNode url="~/Services.aspx" title="Services"/> </siteMapNode></siteMap>
목록 3의 SiteMap 파일은 Home 페이지, Products 페이지 및 Services 페이지의 세 노드를 정의합니다. 각 노드에는 URL 및 제목 특성이 지정되어 있습니다. 목록 4의 마스터 페이지에서는 SiteMapPath 및 Menu 컨트롤에 이 파일을 활용합니다.
목록 4. NavMaster.master
<%@ Master %><html><head> <title>NavMaster</title></head><body> <form id="form1" runat="server"> <table width="100%" border="0" cellpadding="5"> <tr> <td colspan="2"> <asp:Image id="Image1" ImageUrl="~/Logo.gif" Runat="Server" /> </td> </tr> <tr bgcolor="lightblue"> <td colspan="2"> <asp:SiteMapPath id="SiteMapPath1" Runat="Server" /> </td> </tr> </table> <table width="100%" cellpadding="10" border="0"> <tr> <td valign="top" width="100" bgcolor="#eeeeee"> <asp:Menu id="Menu" Runat="Server" DataSourceID="SiteMapDataSource1" StaticDisplayLevels="2" /> </td> <td valign="top"> <asp:contentplaceholder id="ContentColumn" runat="server" /> </td> <td valign="top" width="100" bgcolor="#eeeeee"> <asp:ContentPlaceHolder id="AdColumn" runat="server" > <asp:Image ID="Ad1" ImageUrl="Ad1.gif" Runat="Server" /> <br /> <asp:Image ID="Ad2" ImageUrl="Ad2.gif" Runat="Server" /> </asp:ContentPlaceHolder> </td> </tr> </table> <small>All contents copyright ⓒ 2004 by Microsoft Hair Stylists</small> <asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="server" /> </form></body></html>
목록 4의 마스터 페이지에는 두 개의 ContentPlaceHolder 컨트롤이 포함되어 있습니다. 첫 번째 ContentPlaceHolder 컨트롤은 주 페이지 콘텐츠의 자리 표시자로 사용되며 두 번째 ContentPlaceHolder 컨트롤은 콘텐츠를 광고하는 자리 표시자로 사용됩니다.
두 번째 ContentPlaceHolder 컨트롤에는 기본 콘텐츠가 포함됩니다. 여기에는 배너 광고를 표시하는 데 사용되는 Image 컨트롤이 포함됩니다(그림 5 참조). 특정 콘텐츠 페이지에서 이 기본 콘텐츠를 재정의할 수 있습니다.
그림 5. NavMaster.master 마스터 페이지
마지막으로, 목록 5의 콘텐츠 페이지는 NavMaster.master 마스터 페이지를 기반으로 합니다(그림 6 참조). 이 페이지에는 마스터 페이지의 주 콘텐츠 영역 콘텐츠가 들어 있는 Content 컨트롤이 한 개 있습니다.
그림 6. Products.aspx 페이지
목록 5. Products.aspx
<%@ Page MasterPageFile="~/NavMaster.master" %><asp:Content ID="Content1" ContentPlaceHolderID="ContentColumn" Runat="server"> This is the Products.aspx page</asp:Content>
지금까지 단일 마스터 페이지를 만들고 이 마스터 페이지를 기반으로 콘텐츠 페이지를 만드는 방법을 살펴보았습니다. 단일 웹 사이트에는 여러 마스터 페이지가 포함될 수 있습니다. 예를 들어 웹 사이트에서 뚜렷하게 구분되는 섹션에 대해 다른 마스터 페이지를 만들 수 있습니다.
필요한 경우에는 여러 마스터 페이지를 중첩할 수도 있습니다. 예를 들어 전체 웹 사이트의 마스터 페이지를 하나 만들고 이 사이트 마스터 페이지에 개별 섹션의 마스터 페이지를 중첩할 수 있습니다. Visual Web Developer에서는 이러한 작업을 위한 디자이너 지원을 제공하지 않습니다. 그러므로 마스터 페이지를 중첩하려면 소스 코드 보기에서 작업하거나 메모장을 사용하여 페이지를 만들어야 합니다.
예를 들어 목록 6의 페이지를 Site Master Page에 사용할 수 있습니다. 이 마스터 페이지에는 여는 HTML 태그 및 닫는 HTML 태그, Form 태그 및 단일 ContentPlaceHolder 컨트롤이 포함되어 있습니다.
목록 6. SiteMaster.master
<%@ Master %><html><head> <title>Site Master</title></head><body bgcolor="LightGreen"> <form id="form1" runat="server"> <h1>Site Master Page</h1> <asp:contentplaceholder id="SiteContentPlaceHolder" runat="server" /> </form></body></html>
목록 7의 페이지는 중첩된 마스터 페이지입니다. 이 마스터 페이지는 Site Master Page의 콘텐츠를 재정의합니다. <%@ Master %> 지시문은 SiteMaster.master 마스터 페이지를 참조합니다.
목록 7. SectionMaster.master
<%@ Master MasterPageFile="~/SiteMaster.master" %><asp:content ContentPlaceHolderID="SiteContentPlaceHolder" runat="server" > <table width="100%" bgcolor="LightYellow"> <tr> <td colspan="2"> <h1>Section Master Page</h1> </td> </tr> <tr> <td> <asp:ContentPlaceHolder id="LeftColumn" Runat="Server" /> </td> <td> <asp:ContentPlaceHolder id="RightColumn" Runat="Server" /> </td> </tr> </table> </asp:content>
마지막으로, 목록 8의 콘텐츠 페이지는 Section Master Page를 기반으로 합니다. 이 페이지는 Section Master Page에 중첩된 두 ContentPlaceHolder 컨트롤을 재정의합니다.
목록 8. NestedMasters.aspx
<%@ Page MasterPageFile="~/SectionMaster.master" %><asp:Content ContentPlaceHolderId="LeftColumn" Runat="Server"> This content appears in the left column</asp:Content><asp:Content ContentPlaceHolderId="RightColumn" Runat="Server"> This content appears in the right column</asp:Content>
모든 작업을 수행하고 나면 그림 7의 페이지가 렌더링됩니다. Site Master Page 및 Site Master Page의 콘텐츠가 병합되어 최종 콘텐츠 페이지가 생성됩니다. Site Master Page의 콘텐츠는 녹색으로 표시되고 Section Master page의 콘텐츠는 노란색으로 표시됩니다.
그림 7. 중첩된 마스터 페이지
<%@ Page %> 지시문을 사용하여 콘텐츠 페이지를 마스터 페이지에 연결하는 대신, 웹 응용 프로그램의 구성 파일에서 마스터 페이지를 콘텐츠 페이지에 연결할 수 있습니다. 구성 파일을 사용하면 한 위치에서 여러 콘텐츠 페이지에 연결된 마스터 페이지를 변경할 수 있기 때문에 규모가 큰 웹 사이트를 보다 쉽게 관리할 수 있습니다.
구성 파일의 <pages> 요소에서 마스터 페이지를 설정합니다. 이 요소는 구성 파일의 <system.web> 섹션에 나타납니다. 예를 들어 다음 <pages> 요소는 "SuperMaster.master"를 기본 마스터 페이지로 설정합니다.
<pages masterPageFile="SuperMaster.master" />
구성 파일에서 마스터 페이지를 할당할 때는 두 가지 사항을 알아 두어야 합니다. 첫째로, 콘텐츠 페이지에서 설정한 마스터 페이지가 구성 파일에서 설정한 마스터 페이지보다 우선합니다. 그러므로 Web.Config 파일을 사용하여 마스터 페이지를 설정하려면 콘텐츠 페이지에 MasterPageFile 특성을 포함하지 않아야 합니다.
둘째로, 응용 프로그램은 각각 다른 마스터 페이지를 설정하는 서로 다른 하위 폴더에 있는 Web.Config 파일 두 개 이상을 포함할 수 있습니다. 즉, 새 Web.Config 파일을 만들어 하위 폴더에 있는 Web.Config 파일에서 설정된 마스터 페이지를 재정의할 수 있습니다.
마스터 페이지 작업을 시작한 직후에 발생할 수 있는 한 가지 문제점은 개별 콘텐츠 페이지에서 마스터 페이지의 페이지 제목 및 메타 태그와 같은 속성을 재정의하는 방법입니다. 일반적으로, 같은 마스터 페이지를 기반으로 개별 콘텐츠 페이지를 만들었더라도 각 콘텐츠 페이지마다 고유한 제목을 표시합니다.
특정 콘텐츠 페이지에서 마스터 페이지에 포함된 콘텐츠를 재정의하는 방법에는 여러 가지가 있습니다. 이 섹션에서는 이러한 방법에 대해 설명하겠습니다.
마스터 페이지에서 렌더링된 페이지 제목을 콘텐츠 페이지에서 변경하기만 하려는 경우에는 <%@ Page %> 지시문의 Title 특성을 사용할 수 있습니다. 이 특성은 마스터 페이지에서 서버 쪽 HtmlHead 컨트롤을 사용할 때만 적용됩니다.
예를 들어 목록 9의 마스터 페이지에는 서버 쪽 HtmlHead 컨트롤이 포함되어 있습니다.
목록 9. TitleMaster.master
<%@ Master %><html><head runat="server"> <title>Master Title</title></head><body> <form id="form1" runat="server"> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /> </form></body></html>
목록 9의 <head> 태그에는 runat="server" 특성이 있습니다. 이 특성은 <head> 태그를 서버 쪽 HtmlHead 컨트롤로 변환합니다.
목록 10의 콘텐츠 페이지는 페이지 제목을 재정의합니다. 이 페이지 맨 위에 있는 <%@ Page %> 지시문에는 해당 Title 특성 값이 있습니다. 페이지가 렌더링될 때 페이지 제목으로 "Content Page Title"이 표시됩니다.
목록 10. TitleContent.aspx
<%@ Page MasterPageFile="~/TitleMaster.master" Title="Content Page Title" %><asp:Content ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is some content </asp:Content>
메타 태그나 스타일 태그 등 HTML 헤더의 다른 특성을 재정의해야 하는 경우 콘텐츠 페이지에서 직접 HtmlHead 요소를 참조할 수 있습니다. HtmlHead 컨트롤은 IPageHeader 인터페이스를 구현합니다. 여기에는 다음 속성이 포함됩니다.
콘텐츠 페이지에서 이러한 속성을 수정할 수 있습니다. 예를 들어 목록 11의 마스터 페이지에는 콘텐츠 페이지에서 재정의할 수 있는 서버 쪽 HtmlHead 컨트롤이 있습니다.
목록 11. HeaderMaster.master
<%@ Master %><html><head runat="server"> <title>Master Title</title></head><body> <form id="form1" runat="server"> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /> </form></body></html>
목록 12의 콘텐츠 페이지는 HtmlHead 컨트롤의 Title 및 Metadata 속성을 수정하여 사용자 지정 콘텐츠를 표시합니다.
목록 12. HeaderContent.aspx(Microsoft Visual Basic .NET)
<%@ Page Language="VB" MasterPageFile="~/HeaderMaster.master" %><script runat="server"> Sub Page_Load() Master.Page.Header.Title = "Content Title" Master.Page.Header.Metadata.Add("Keywords", "blah,blah") Master.Page.Header.Metadata.Add("Description", "blah,blah") End Sub </script><asp:Content ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is some content </asp:Content>
목록 12. HeaderContent.aspx(c#)
<%@ Page Language="c#" MasterPageFile="~/HeaderMaster.master" %><script runat="server"> void Page_Load() { Master.Page.Header.Title = "Content Title"; Master.Page.Header.Metadata.Add("Keywords", "blah,blah"); Master.Page.Header.Metadata.Add("Description", "blah,blah"); } </script><asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is some content </asp:Content>
Page 개체의 Master 속성은 콘텐츠 페이지의 마스터 페이지를 참조합니다. 원하는 경우에는 Master 대신 Page.Master를 사용할 수도 있습니다. Header 속성은 HtmlHead 요소를 참조합니다. 목록 12의 콘텐츠 페이지는 HtmlHead 컨트롤의 Title 및 Metadata 속성을 수정합니다.
마스터 페이지의 콘텐츠를 더 상세히 조정해야 할 경우 마스터 페이지에서 속성 및 메서드를 제공할 수 있습니다. 마스터 페이지에서 제공한 공용 속성을 콘텐츠 페이지에서 수정할 수 있으며, 마스터 페이지에서 제공한 공용 메서드를 콘텐츠 페이지에서 호출할 수 있습니다.
예를 들어 콘텐츠 페이지에서 마스터 페이지 바닥글의 콘텐츠를 수정할 수 있습니다. 목록 13의 마스터 페이지는 Footer라는 공용 속성을 제공합니다.
목록 13. FooterMaster.master(Visual Basic .NET)
<%@ Master Language="VB" %><script runat="server"> Private _footer As String Public Property Footer() As String Get Return _footer End Get Set(ByVal value As String) _footer = value End Set End Property </script><html><head runat="server"> <title>Footer Master</title></head><body> <form id="form1" runat="server"> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /> <br /> <small><%= _footer %></small> </form></body></html>
목록 13. FooterMaster.master(C#)
<%@ Master Language="C#" %><script runat="server"> private string _footer; public string Footer { get { return _footer; } set { _footer = value; } } </script><html><head id="Head1" runat="server"> <title>Footer Master</title></head><body> <form id="form1" runat="server"> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /> <br /> <small><%= _footer %></small> </form></body></html>
목록 13에서 공용 Footer 속성은 _footer라는 개인 필드를 수정합니다. 개인 _footer 필드는 인라인 식 <%= _footer %>를 사용하여 마스터 페이지의 맨 아래에 표시됩니다.
목록 14의 콘텐츠 페이지는 Footer 속성을 설정합니다. Footer 속성은 Page 개체의 Master 속성에 의해 제공됩니다. 일반적으로 Master 속성은 MasterPage 개체를 나타냅니다. 그러나 이 콘텐츠 페이지에는 Master 속성 값을 FooterMaster 개체로 캐스팅하는 <%@ MasterType %> 지시문이 포함됩니다.
목록 14. FooterContent.aspx(Visual Basic .NET)
<%@ Page Language="VB" MasterPageFile="~/FooterMaster.master" %><%@ MasterType VirtualPath="~/FooterMaster.master" %><script runat="server"> Sub Page_Load() Master.Footer = "Custom Page Footer" End Sub </script><asp:Content ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is some content </asp:Content>
목록 14. FooterContent.aspx(C#)
<%@ Page Language="C#" MasterPageFile="~/FooterMaster.master" %><%@ MasterType VirtualPath="~/FooterMaster.master" %><script runat="server"> void Page_Load() { Master.Footer = "Custom Page Footer"; } </script><asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is some content </asp:Content>
마스터 페이지에서 속성과 메서드를 제공하여 마스터 페이지의 렌더링 관련 항목을 수정할 수 있습니다.
이 마지막 섹션에서는 마스터 페이지의 고급 응용 프로그램에 대해 살펴봅니다. 또한 실행 중에 여러 마스터 페이지를 동적으로 로드하는 방법도 설명합니다.
마스터 페이지를 동적으로 로드하는 것이 유용한 경우가 두 가지 있습니다. 우선, 사용자의 웹 사이트에서 하나 이상의 파트너 웹 사이트와 공동 상표를 사용해야 하는 경우가 있습니다. 파트너 구성원이 파트너 웹 사이트에서 사용자의 웹 사이트에 연결하는 경우 파트너 웹 사이트의 모양 및 느낌과 일치하는 마스터 페이지를 자동으로 로드할 수 있습니다.
마스터 페이지를 동적으로 로드하는 두 번째 경우는 응용 프로그램 사용자가 페이지 레이아웃을 선택할 수 있도록 하는 경우입니다. 이 경우 사용자에게 표준 마스터 페이지 집합을 제공할 수 있습니다. 그러면 응용 프로그램 사용자는 원하는 마스터 페이지를 선택하여 원하는 페이지 레이아웃을 선택할 수 있습니다.
Page 개체의 MasterPageFile 속성에 값을 할당하여 마스터 페이지를 동적으로 로드할 수 있습니다. 이 속성에 할당된 값은 유효한 마스터 페이지 파일의 상대 경로여야 합니다.
MasterPageFile 속성을 사용할 때 주의해야 할 중요한 제한 사항이 있습니다. Page PreInit 이벤트 전이나 이벤트 동안에만 이 속성에 값을 할당할 수 있습니다. PreInit는 페이지 실행 주기에서 첫 번째 이벤트입니다. Page Load 이벤트 등 나중에 발생하는 이벤트 동안 이 속성에 값을 할당하면 예외가 발생합니다. 마스터 페이지에 따라 서로 다른 컨트롤 집합이 페이지에 로드되기 때문입니다.
목록 15의 콘텐츠 페이지는 MasterPageFile 속성을 사용하여 실행 중에 서로 다른 마스터 페이지를 동적으로 로드합니다.
목록 15. DynamicContent.aspx(Visual Basic .NET)
<%@ Page Language="VB" MasterPageFile="~/DynamicMaster1.master" %><script runat="server"> Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs) MasterPageFile = Profile.Master End Sub</script><asp:Content ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is the content</asp:Content>
목록 15. DynamicContent.aspx(C#)
<%@ Page Language="c#" MasterPageFile="~/DynamicMaster1.master" %><script runat="server"> void Page_PreInit(Object sender, EventArgs e) { MasterPageFile = Profile.Master; }</script><asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> Here is the content</asp:Content>
목록 15에서 마스터 페이지는 PreInit 이벤트에서 동적으로 로드됩니다. 이 경우 마스터 페이지 파일의 경로는 사용자의 프로필에서 로드됩니다. 프로필을 사용하여 사용자와 관련된 정보를 영구적으로 저장할 수 있습니다. 이 방법을 사용하면 응용 프로그램에서 사용자가 페이지 간을 이동할 때 사용자가 선택한 마스터 페이지가 손실되지 않습니다.
사용자 프로필을 사용하려면 다음 구성 설정을 응용 프로그램 Web.Config 파일의 <system.web> 섹션에 추가해야 합니다.
<anonymousIdentification enabled="true" /> <profile> <properties> <add name="Master" allowAnonymous="true" defaultValue="DynamicMaster1.master" /> </properties> </profile>
이 설정은 익명 사용자와 인증된 사용자가 모두 사용할 수 있는 Master라는 새 Profile 속성을 만듭니다.
목록 15의 콘텐츠 페이지는 DynamicMaster1.master와 DynamicMaster2.master라는 두 마스터 페이지 중 하나를 로드합니다. DynamicMaster1.master의 소스 코드는 목록 16에 있고, DynamicMaster2.master의 소스 코드는 목록 17에 있습니다. 두 마스터 파일은 이름과 배경색이 다르다는 점을 제외하고는 동일합니다.
목록 16. DynamicMaster1.master(Visual Basic .NET)
<%@ Master Language="vb" %><script runat="server"> Sub Page_Load() If Not IsPostBack Then dropMaster.SelectedValue = Profile.Master End If End Sub Sub SelectMaster(ByVal s As Object, ByVal e As EventArgs) Profile.Master = dropMaster.SelectedValue Response.Redirect(Request.Path) End Sub </script><html><head> <title>Dynamic Master 1</title></head><body bgcolor="LightYellow"><form runat="server"><h1>Dynamic Master 1</h1><p><asp:DropDownList id="dropMaster" AutoPostBack="true" OnSelectedIndexChanged="SelectMaster" ValidationGroup="Master" Runat="Server"> <asp:ListItem Text="Dynamic 1" value="DynamicMaster1.master" /> <asp:ListItem Text="Dynamic 2" value="DynamicMaster2.master" /></asp:DropDownList></p><asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /></form></body></html>
목록 16. DynamicMaster1.master(C#)
<%@ Master Language="c#" %><script runat="server"> void Page_Load() { if (!IsPostBack) dropMaster.SelectedValue = Profile.Master; } void SelectMaster(Object s, EventArgs e) { Profile.Master = dropMaster.SelectedValue; Response.Redirect(Request.Path); } </script><html><head> <title>Dynamic Master 1</title></head><body bgcolor="LightYellow"><form id="Form1" runat="server"><h1>Dynamic Master 1 CS</h1><p><asp:DropDownList id="dropMaster" AutoPostBack="true" OnSelectedIndexChanged="SelectMaster" ValidationGroup="Master" Runat="Server"> <asp:ListItem Text="Dynamic 1" value="DynamicMaster1.master" /> <asp:ListItem Text="Dynamic 2" value="DynamicMaster2.master" /></asp:DropDownList></p><asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /></form></body></html>
목록 17. DynamicMaster2.master(Visual Basic .NET)
<%@ Master Language="vb" %><script runat="server"> Sub Page_Load() If Not IsPostBack Then dropMaster.SelectedValue = Profile.Master End If End Sub Sub SelectMaster(ByVal s As Object, ByVal e As EventArgs) Profile.Master = dropMaster.SelectedValue Response.Redirect(Request.Path) End Sub </script><html><head> <title>Dynamic Master 2</title></head><body bgcolor="LightGreen"><form id="Form1" runat="server"><h1>Dynamic Master 2</h1><p><asp:DropDownList id="dropMaster" AutoPostBack="true" OnSelectedIndexChanged="SelectMaster" ValidationGroup="Master" Runat="Server"> <asp:ListItem Text="Dynamic 1" value="DynamicMaster1.master" /> <asp:ListItem Text="Dynamic 2" value="DynamicMaster2.master" /></asp:DropDownList></p><asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /></form></body></html>
목록 17. DynamicMaster2.master(C#)
<%@ Master Language="c#" %><script runat="server"> void Page_Load() { if (!IsPostBack) dropMaster.SelectedValue = Profile.Master; } void SelectMaster(Object s, EventArgs e) { Profile.Master = dropMaster.SelectedValue; Response.Redirect(Request.Path); } </script><html><head> <title>Dynamic Master 2</title></head><body bgcolor="LightGreen"><form id="Form1" runat="server"><h1>Dynamic Master 2 CS</h1><p><asp:DropDownList id="dropMaster" AutoPostBack="true" OnSelectedIndexChanged="SelectMaster" ValidationGroup="Master" Runat="Server"> <asp:ListItem Text="Dynamic 1" value="DynamicMaster1.master" /> <asp:ListItem Text="Dynamic 2" value="DynamicMaster2.master" /></asp:DropDownList></p><asp:contentplaceholder id="ContentPlaceHolder1" runat="server" /></form></body></html>
두 마스터 페이지에는 사용자가 특정 마스터 페이지를 선택할 수 있는 DropDownList 컨트롤이 있습니다. 마스터 페이지를 선택하면 SelectMaster 메서드가 호출됩니다. 이 메서드는 선택된 마스터 페이지를 사용자 프로필에 할당하고 현재 페이지를 다시 로드합니다. PreInit 이벤트 동안 새로 선택한 마스터 페이지를 로드해야 하기 때문에 페이지 다시 로드 작업이 필요합니다.
개인적으로 마스터 페이지는 ASP.NET 2.0에서 필자가 가장 좋아하는 새 기능입니다. 이 새 기능은 앞으로 ASP.NET 응용 프로그램을 만드는 방법에 가장 큰 영향을 미칠 것입니다. 현재는 익숙치 않은 사용자 컨트롤이나 사용자 지정 기반 Page 클래스를 통해 다시 사용할 수 있는 페이지 레이아웃을 만들고 있습니다만, 마스터 페이지를 사용하면 이 작업을 보다 명확하고 직관적인 방식으로 수행할 수 있습니다. 또한, 무엇보다 Microsoft Visual Studio .NET 2005는 디자이너 기능을 완벽하게 지원하므로 페이지 레이아웃을 만드는 동안 페이지 모양을 미리 볼 수 있습니다.
Stephen Walther는 ASP.NET 관련 베스트셀러 서적인 ASP.NET Unleashed의 저자입니다. 또한 Microsoft에서 만든 샘플 ASP.NET 응용 프로그램인 ASP.NET Community Starter Kit 설계자 및 수석 개발자입니다. Stephen의 회사인 Superexpert(http://www.superexpert.com/ )에서는 NASA와 Microsoft를 비롯하여 미국 전역의 회사에 대해 ASP.NET 교육을 제공했습니다
[펌]ASP.NET Whidbey의 향상된 캐싱 기능 (0) | 2006.03.06 |
---|---|
[펌] ASP.NET 기본 제공 기능을 활용하여 웹 공격 차단 (0) | 2006.02.09 |
[펌] ASP.NET 2.0 내부 변경 사항 (0) | 2006.01.16 |
VS2005 에서 aspx 파일 생성할때 XHTML 문법 체크때문에 ㅎㅎ (0) | 2006.01.16 |
NET Framework V2.0 Obsolete API List (0) | 2006.01.13 |
<identity impersonate="true" userName="administrator" password="1111"/>
[펌] HTTP 모듈과 처리기를 사용하여 플러그형 ASP.NET 구성 요소 만.. (0) | 2006.02.01 |
---|---|
[펌] Smart Client를 이용한 파일 업로드 (0) | 2006.01.18 |
[펌]Quick and Dirty Guide to Configuring Log4Net For Web Applications (0) | 2006.01.09 |
http://www.devintelligence.com/Log4NetViewer/ (0) | 2006.01.09 |
Log4net 을 이렇게 보기 편하게 해주다뉘... (0) | 2006.01.09 |
Jayesh Patel, Bryan Acker, Robert McGovern
Infusion Development
2004년 8월
적용 대상:
Microsoft ASP.NET 2.0
요약: ASP.NET 2.0은 이전 버전인 ASP.NET 1.1과 완벽하게 호환되지만, ASP.NET의 많은 요소들이 내부적으로 변경되었습니다. 변경된 요소에는 코드 모델, 컴파일, 페이지 주기 등이 있습니다. 이 기사에서는 이러한 변경 사항에 대해 간단히 설명합니다(21페이지/인쇄 페이지 기준).
소개
코드 모델
컴파일
실행 중에 전체 컴파일(코드 디렉터리)
페이지 주기
확장성
고급 캐싱 기술
성능
결론
전문 ASP.NET 개발자에게 있어서 ASP.NET 2.0의 큰 문제점은 내부 변경 사항과 연관되어 있습니다. 새로운 기능을 배우는 것은 흥미롭고 재미있습니다. 더욱이, ASP.NET 핵심 구조의 변경 사항은 해당 기술을 숙달하고자 하는 개발자에게 보다 큰 흥밋거리로 다가옵니다. 이 백서에서는 버전 1.x 이후의 ASP.NET 2.0 내부 구조 변경 사항에 대해 알아봅니다.
이 백서에서 다루는 항목은 성능을 중요시하는 개발자 및 기술 설계자가 응용 프로그램을 미세 조정하는 데 유용합니다. 특히 코드 모델, 컴파일, 페이지 주기, 확장성, 성능 및 캐싱과 같은 주요 영역에 대해 살펴봅니다.
이 문서에 사용된 대부분의 예를 이해하려면 ASP.NET, Visual Basic .NET 및/또는 C# 구문에 익숙해야 합니다. 해당하는 경우에는 특정 주제에 대한 자세한 설명을 볼 수 있도록 참조 문서가 제공되어 있습니다.
ASP.NET 2.0에서 가장 명백하게 나타나는 내부 변경 사항은 ASP.NET 웹 페이지를 만드는 방법입니다. 이 섹션에서는 코드 숨김 모델의 변경 사항 및 이 변경 사항이 ASP.NET 개발에 미치는 영향에 대해 설명합니다.
ASP.NET 1.x에서는 개발자가 Web Form을 개발할 때 선택할 수 있는 두 가지 주요 옵션이 있었습니다. 첫째로, 개발자는 일반 ASP 모델에 따라 ASPX 페이지에서 직접 코드를 작성할 수 있었습니다. 코드 인라인이라는 이 과정은 단순한 명령에는 적합합니다. 그러나 보다 복잡한 코드의 경우 코드 인라인을 작성하면 표현(HTML)과 기능(코드)이 혼합된 웹 페이지를 읽기가 어려워집니다. ASP.NET의 기본 코딩 작업은 이러한 문제를 해결하기 위해 변경되었습니다. 코드 숨김 파일이라는 별도의 코드 전용 파일에서 비즈니스 논리 및 이벤트 처리 코드를 작성할 수 있습니다. 코드 숨김 모델은 프레젠테이션 태그가 포함된 ASPX 파일에 코드 전용 파일을 연결합니다. 표현과 코드를 분리함으로써 개발 팀에서 디자이너는 프레젠테이션 파일에서 작업하고 개발자는 코드 파일에서 작업하도록 하여 보다 신속하게 작업할 수 있습니다.
그림 1. ASP.NET 1.x 코딩 모델
코드 숨김 모델의 주요 문제점은 코드 숨김 파일을 ASPX 페이지와 동기화하는 방법이었습니다. 프로그래밍 관점에서 볼 때 ASPX 페이지가 코드 숨김 파일에서 상속되는 경우에도, 사실 두 파일은 더욱 복잡한 관계로 연결되어 있었습니다.
ASP.NET 1.x의 코드 숨김 모델에 대한 자세한 내용은 MSDN Library 기사 Web Forms 코드 모델 을 참조하십시오.
ASP.NET의 디자인 패러다임은 개발자가 Microsoft Visual Studio .NET을 사용하여 컨트롤을 ASPX 페이지에 끌어 놓는 것이었습니다. 그러면 Visual Studio에서 코드 숨김 파일에 적합한 지원 코드를 자동으로 생성합니다. 컨트롤을 ASPX 페이지에 추가하면 새 코드를 코드 숨김 파일에 추가해야 합니다. 즉, 코드 숨김 파일이 ASPX 페이지에서 상속되는 경우에도 ASPX 페이지는 실제로 코드 숨김 파일의 디자인을 사용합니다.
동기화의 두 번째 문제는 파일 컴파일 방법이었습니다. 모든 코드 숨김 파일은 지원 클래스와 함께 어셈블리로 컴파일되어 웹 응용 프로그램의 /bin 디렉터리에 저장됩니다. 컴파일 단계는 응용 프로그램 배포 이전에 이루어지는 반면, ASPX 페이지는 페이지를 처음 요청할 때 실행 중에 컴파일됩니다. ASP.NET 런타임은 실제로 ASPX 페이지를 고유한 임시 어셈블리로 컴파일합니다.
이 과정에서 발생하는 문제는 코드 숨김 어셈블리가 업데이트되지 않는 상태에서 ASPX 페이지를 변경할 수 있다는 점입니다. 즉, 개발자는 배포 후 ASPX 페이지에서 속성을 수정하거나 컨트롤의 형식을 변경할 수 있습니다. 이때 코드 숨김 파일은 업데이트되지 않으며 응용 프로그램 어셈블리도 다시 컴파일되지 않습니다. 이러한 경우 코드 숨김 파일과 연결된 ASPX 페이지가 일치하지 않기 때문에 응용 프로그램에서 예기치 않은 오류가 발생할 수 있습니다.
ASP.NET 2.0에서도 코드 인라인 및 코드 숨김 코딩 모델을 모두 제공합니다. 코드 인라인 모델의 경우 Microsoft Visual Studio 2005에서 단일 파일 개발을 지원하는 방식을 제외하고는 거의 변경된 것이 없습니다. Visual Studio 2005의 변경 사항 및 코드 인라인 처리 방법에 대한 자세한 내용은 이 기사 를 참조하십시오.
ASP.NET 2.0에서는 코드 숨김 파일의 특성을 수정하여 코드 숨김 모델의 상속 및 컴파일 문제를 모두 해결했습니다. ASP.NET 2.0에서 코드 숨김 파일은 더 이상 System.Web.UI.Page 클래스의 완전한 구현이 아니며, 부분 클래스라는 새로운 구조로 되어 있습니다. 부분 클래스에는 사용자가 정의한 코드가 모두 포함되어 있지만, ASP.NET 1.x의 Visual Studio .NET에서 자동으로 생성된 모든 통로 및 연결 코드는 생략되어 있습니다. 새 코드 숨김 파일이 있는 ASPX 페이지를 요청하면 ASP.NET 2.0 런타임이 실제로 ASPX 페이지와 부분 클래스를 별도의 두 클래스가 아닌 단일 클래스로 결합합니다.
그림 2. ASP.NET 2.0의 코드 숨김 모델
부분 클래스에서는 새 키워드(Visual Basic의 Expands 또는 C#의 Partial)를 사용하여 실행 중에 클래스의 코드가 다른 클래스와 병합되도록 지정합니다. 마찬가지로, ASPX 페이지에서는 compilewith라는 새 지시문을 사용하여 코드 숨김 파일과 연결되도록 지정합니다.
일반 ASP.NET 1.x 코드 숨김 파일에 친숙한 경우 Visual Studio에서 자동으로 생성된 컨트롤 선언 및 초기화 코드를 삽입한다는 것을 알고 있을 것입니다. 자동으로 생성된 이 코드는 코드 숨김 파일과 ASPX 파일이 양방향으로 동기화되어 직접적으로 생기는 결과입니다. 레이블이 있는 일반 ASPX 페이지에는 자동으로 생성된 여러 텍스트 줄로 구성된 해당 코드 숨김 파일이 있습니다.
목록 1. ASP.NET 1.x의 코드 숨김 파일
namespace WebApplication1{ public class WebForm1 : System.Web.UI.Page에서 { protected System.Web.UI.WebControls.Label Label1; private void Page_Load(object sender, System.EventArgs e) { } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { InitializeComponent(); base.OnInit(e); } private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion }}
자동으로 생성된 코드는 레이블(굵게 표시된 줄)을 정의할 뿐 아니라 새 이벤트(페이지 로드)를 선언하고 자동으로 생성된 메서드 래퍼(Page_Load())에 이 이벤트를 자동으로 연결하기도 합니다.
이에 비해 ASP.NET 2.0에서 같은 ASP.NET 페이지는 훨씬 깔끔한 코드 숨김 파일을 생성합니다.
목록 2. ASP.NET 2.0의 코드 숨김 파일
namespace ASP {public partial class Webform1_aspx{}}
개발자는 Label1에 자동으로 액세스하여 필요에 따라 이벤트를 추가할 수 있습니다. 예를 들어 Page_Load 이벤트를 추가하여 레이블을 초기화할 수 있습니다.
목록 3. 새 코드 숨김 파일의 이벤트 추가 작업
namespace ASP {public partial class Webform1_aspx{ void Page_Load(object sender, EventArgs e) { Label1.Text = "Hello ASP.NET 2.0"; }}}
이벤트 구문은 Visual Studio .NET을 통해 생성할 수 있습니다. 결과로 생성되는 코드 숨김 파일은 길이가 훨씬 짧고 자동 생성 코드가 없습니다. ASP.NET 런타임은 코드 숨김 파일의 이벤트를 ASPX의 컨트롤에 자동으로 연결합니다. 즉, ASP.NET 런타임은 이제 Visual Studio에서 수행했던 코드 생성 작업을 자동으로 수행합니다.
새 코드 숨김 모델에서는 상속의 복잡성이 크게 줄었습니다. ASPX 페이지가 코드 숨김 파일에서 직접 상속되지 않으므로, 코드 숨김 파일은 ASPX 페이지에서 정의되는 모든 컨트롤을 더 이상 정의 및 지원하지 않아도 됩니다. 마찬가지로 코드 숨김 파일은 ASP.NET 1.x에서는 필요했던 선언 코드가 없어도 ASPX 페이지에서 컨트롤에 자동으로 액세스할 수 있습니다. ASP.NET 런타임이 필요한 선언 및 이벤트 작성 코드를 컴파일된 최종 파일에 자동으로 삽입하기 때문에 이 모든 기능이 가능한 것입니다. 런타임이 이 작업을 처리하므로 코드 개발자나 웹 개발자는 이에 대해 신경쓰지 않아도 됩니다.
디자인하는 동안 링크는 Visual Studio 2005에서 관리됩니다. Visual Studio 환경에서는 ASP.NET 런타임 컴파일을 사용하여 코드 개발자와 웹 개발자가 동기화하면서 작업할 수 있도록 합니다.
새 코드 숨김 파일은 ASPX 페이지에 결합되고 실행 중에 완전한 단일 클래스로 컴파일되기 때문에 컴파일이 전혀 복잡하지 않습니다. 즉, 코드 숨김 파일은 ASPX 페이지와 자동으로 동기화됩니다. 새 컴파일 모델을 사용해도 코드가 동기화되지 않을 수 있지만, 그 결과로 발생하는 예외가 훨씬 명확하기 때문에 문제점을 빨리 파악할 수 있습니다.
ASP.NET 1.x에 도입된 페이지 모델로 인해 ASP.NET 웹 페이지의 컴파일 과정은 항상 두 단계로 나눠져 있었습니다. 먼저 코드 숨김 파일 및 기타 지원 클래스가 어셈블리로 컴파일된 다음, 실행 중에 개별 ASPX 파일이 컴파일됩니다. 이 모델에는 많은 장점이 있지만 몇 가지 단점도 있습니다. ASP.NET 2.0에서는 사용자의 특정 요구에 따라 보다 광범위한 컴파일 옵션을 제공함으로써 이 기본 모델에 대한 몇 가지 대안을 제공합니다.
ASP.NET 1.x의 기본 컴파일 모델은 요청된 각 ASPX 페이지에 대해 하나의 응용 프로그램 어셈블리(컴파일된 모든 코드 숨김 파일 및 기타 소스 코드 포함) 및 하나의 임시 어셈블리를 만들었습니다. 일괄 처리와 같은 컴파일러 최적화로 인해 임시 ASPX 페이지가 동일한 어셈블리로 컴파일되는 경우도 있습니다. 두 가지 경우 모두 각 ASPX 페이지는 임시 어셈블리로 컴파일되기 때문에 ASP.NET 런타임으로 로드할 수 있습니다.
그림 3. ASP.NET 1.x의 컴파일
이 모델에는 장점도 있지만, 두 가지 주요 단점이 있습니다. 첫째로, ASPX 페이지는 읽을 수 있는 형식으로 웹 사이트에 배포해야 합니다. 개발자가 코드 인라인 모델을 사용한 경우에는 일부 또는 전체 비즈니스 논리를 프로덕션 서버에서 배포할 수도 있습니다. 원시 ASPX 페이지를 제공하지 않도록 IIS 및 ASP.NET을 구성한 경우에도, 기술력이 높은 공격자는 웹 서버 액세스를 통해 여전히 파일에 액세스할 수 있습니다. 둘째로, ASP.NET 런타임이 ASPX 페이지를 컴파일해야 하기 때문에 웹 페이지를 처음 요청할 때는 응답이 보통 때보다 늦습니다.
개발자가 이 프로세스에 대해 제어할 수 있는 유일한 사항은 ASPX 페이지 일괄 컴파일 여부입니다. ASP.NET 1.x에서는 <compilation> 태그를 수정하여 web.config 파일에서 일괄 컴파일을 구성할 수 있습니다.
목록 4. 일괄 컴파일 구성
<compilation batch="true|false" batchTimeout="시간(초)" maxBatchSize="일괄 컴파일당 최대 페이지 수" maxBatchGeneratedFileSize="일괄 컴파일당 생성되는 소스 파일의 최대 결합 크기(KB)" </compilation>(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사에는 설명을 위해 번역문으로 제공됩니다.)
일괄 컴파일을 사용하면 웹 페이지를 처음 요청할 때 시작 시간은 길어지는 대신 로드 시간이 줄어듭니다. 일괄 컴파일의 두 번째 장점은 모든 ASPX 파일이 페이지당 하나의 임시 어셈블리로 컴파일되지 않고 단일 임시 어셈블리로 컴파일된다는 점입니다.
ASP.NET 2.0에서는 웹 응용 프로그램에 대해 다음과 같은 4가지 컴파일 모델을 제공합니다.
환경과 요구 사항에 가장 적합한 컴파일 옵션을 선택할 수 있지만, 컴파일 모델에는 항상 융통성이 있습니다. 코드 디렉터리를 사용하여 코드 숨김 파일을 저장하는 경우에도 전체 컴파일 방법을 사용하여 응용 프로그램을 배포할 수 있습니다.
ASP.NET 2.0에서도 web.config 일괄 컴파일 설정을 사용할 수 있습니다. 일괄 컴파일의 장점은 첫 사용자가 페이지를 즉시 사용할 수 있으며, 일괄 컴파일 작업 중에 ASPX 페이지의 오류가 검색된다는 점입니다. 그러나 일괄 컴파일을 사용하면 응용 프로그램을 시작할 때 지연이 발생하며 web.config 파일에서 일괄 컴파일을 구성해야 합니다.
미리 컴파일하여 배포하는 경우 웹 사이트의 실행 파일 버전인 어셈블리를 하나 이상 만들 수 있습니다. 그 결과로 생기는 어셈블리에는 웹 사이트의 컴파일 코드가 포함됩니다. HTML 페이지, 리소스, 구성 파일 및 ASPX 페이지는 별도로 복사됩니다.
미리 컴파일하여 배포하려면 aspnet_compiler.exe라는 명령줄 유틸리티를 사용해야 합니다. 이 유틸리티는 대상 배포 디렉터리를 만드는데, 이 디렉터리에는 다양한 ASPX 페이지의 어셈블리 및 스텁 파일이 있는 /bin 디렉터리가 포함되어 있습니다. 이 유틸리티를 사용하면 "magic page"(마법 페이지)를 호출하는 동작과 비슷하게 현재 위치에서 미리 컴파일할 수도 있습니다. 스텁 파일은 ASPX 페이지와 이름이 같지만 컴파일된 어셈블리로 호출되는 단순 코드를 포함하고 있습니다. 즉, ASPX 페이지는 완전한 기능을 갖춘 페이지라기보다는 단순히 빈 셸입니다.
웹 사이트를 미리 구성하여 배포하면 어셈블리를 디컴파일하지 않고서는 코드에 액세스할 수 없기 때문에 보안이 크게 향상됩니다. 보안을 더욱 향상시키려면 컴파일의 결과물인 어셈블리를 판독하기 어렵게 처리하여 웹 응용 프로그램을 더욱 안전하게 만들 수 있습니다. 미리 컴파일하여 배포하는 방법의 가장 큰 단점은 이 단계를 배포 전에 수행해야 하기 때문에 배포한 후에는 웹 사이트를 변경할 수 없다는 점입니다. 웹 사이트를 변경하려면 웹 사이트를 다시 컴파일하여 다시 배포해야 합니다.
미리 컴파일하여 배포하는 옵션은 웹 서버에 배포되는 원시 코드의 양을 줄이고 최고의 보안을 제공하기 때문에 대부분의 주요 웹 응용 프로그램에서 배포에 사용되는 메커니즘입니다. 생산성을 크게 저하시키지 않고 이 향상된 프로세스를 일반 개발/테스트/배포 주기에 포함할 수 있습니다.
지금까지 설명한 세 가지 컴파일 방법 모두, 배포하기 전에 모든 코드 파일(코드 숨김 파일 및 지원 클래스)을 컴파일해야 합니다. ASP.NET 2.0에서는 코드 디렉터리를 사용할 수 있습니다.
코드 디렉터리는 컴파일되지 않은 클래스를 보관하는 특수 디렉터리입니다. 실행 중에 ASP.NET 런타임은 응용 프로그램에서 ASPX 페이지가 자동으로 참조하는 어셈블리로 이 디렉터리의 콘텐츠를 컴파일합니다. 즉, 코드 디렉터리를 사용함으로써 지원 코드에 대해 별도의 어셈블리를 만들고 참조하지 않아도 됩니다. 코드 디렉터리의 장점은 프로젝트를 완전히 컴파일하지 않고 배포할 수 있으므로 잠재적인 불일치 문제를 줄일 수 있다는 점이며, 단점은 서버에서 컴파일되지 않은 코드가 노출된다는 점입니다.
이 옵션은 코드 숨김 파일 또는 외부 개체의 형식으로 지원 코드가 많이 필요하지 않은 ASP.NET 응용 프로그램에 적합합니다. 간단한 응용 프로그램의 경우에는 시스템을 빠르게 배포 및 테스트할 수 있는 방법을 사용하는 것이 보다 강력한 컴파일 방법을 사용하는 것에 비해 더 유리합니다.
ASP.NET 2.0에서는 ASP.NET 페이지의 주기에서 두 가지 주요 사항이 변경되었습니다. 첫째로, ASP.NET 2.0에서는 새 이벤트를 제공하여 마스터 페이지, 개인 설정, 통합 모바일 장치 지원 등의 새 기능을 지원합니다. 둘째로, ASP.NET 2.0에는 Web Forms의 페이지 간 게시 기능이 도입되었습니다.
ASP.NET 2.0에서는 ASP.NET 1.x에 비해 보다 세분화된 페이지 주기 메서드 스택을 제공합니다. 추가된 메서드는 웹 개발자에게 보다 향상된 제어 기능을 제공합니다. ASP.NET 페이지의 Page 개체를 통해 이러한 이벤트에 액세스할 수 있습니다.
표 1은 광범위한 메서드 목록을 보여 줍니다. 메서드 열에는 실제 이벤트 메서드 이름이 표시되며, 활성 열은 이벤트가 항상 활성 상태인지 아니면 PostBack 작업 동안에만 활성화되는지를 나타냅니다. 예를 들어 새 TestDeviceFilter 메서드를 사용하여 어떤 장치 필터가 있는지 확인할 수 있으며 이 정보를 통해 페이지 표시 방법을 결정할 수 있습니다. 반면에 새 LoadControlState 메서드는 포스트백(postback) 동안에만 활성화됩니다. SaveControlState와 함께 이 메서드를 재정의하여 포스트백(postback) 동안 컨트롤 상태를 저장 및 복원하기 위한 대체 serialization 구성표를 만들 수 있습니다.
표 1. 페이지 주기 메서드
메서드 | 활성 |
---|---|
Constructor | 항상 |
Construct | 항상 |
TestDeviceFilter | 항상 |
AddParsedSubObject | 항상 |
DeterminePostBackMode | 항상 |
OnPreInit | 항상 |
LoadPersonalizationData | 항상 |
InitializeThemes | 항상 |
OnInit | 항상 |
ApplyControlSkin | 항상 |
ApplyPersonalization | 항상 |
OnInitComplete | 항상 |
LoadPageStateFromPersistenceMedium | PostBack |
LoadControlState | PostBack |
LoadViewState | PostBack |
ProcessPostData1 | PostBack |
OnPreLoad | 항상 |
OnLoad | 항상 |
ProcessPostData2 | PostBack |
RaiseChangedEvents | PostBack |
RaisePostBackEvent | PostBack |
OnLoadComplete | 항상 |
OnPreRender | 항상 |
OnPreRenderComplete | 항상 |
SavePersonalizationData | 항상 |
SaveControlState | 항상 |
SaveViewState | 항상 |
SavePageStateToPersistenceMedium | 항상 |
Render | 항상 |
OnUnload | 항상 |
페이지 주기에 대해 간단히 살펴보면, 테마와 개인 설정 같이 ASP.NET 2.0에서 사용할 수 있는 여러 기능이 자연스럽게 구현되는 위치를 볼 수 있습니다. 예를 들어 테마는 IntializeThemes 이벤트에서 처리되며 개인 설정 데이터는 LoadPersonalizationData에서 로드된 다음 나중에 ApplyPersonalization 메서드에서 적용됩니다. 어떤 UI 요소가 웹 응용 프로그램의 최종적인 모양과 느낌을 결정하는지와 관련하여 메서드 순서는 매우 중요합니다.
페이지 주기의 두 번째 주요 변경 사항은 포스트백(post back) 이벤트 및 Web Forms 관련 사항입니다. ASP.NET 1.x에서는 Web Forms가 호스트 페이지로 자동 포스트백(postback)됩니다. 즉, 사용자가 양식을 제출하면 양식 데이터는 원래 양식이 포함된 페이지로 항상 다시 전송됩니다. 이 방법으로 디자인하면 컨트롤 상태를 쉽게 저장할 수 있지만 개발자가 보다 복잡한 작업을 수행하는 데 제한이 있습니다.
ASP.NET 2.0에서는 개발자가 양식 데이터를 제출하는 위치를 결정할 수 있는 새 속성이 Web Form 컨트롤에 포함되어 있습니다. 대부분의 경우에는 포스트백(postback) 메커니즘이 적합하므로 여전히 이 메커니즘이 기본값입니다. 그러나 이제 개발자는 다른 데이터를 다른 양식에 게시할 수도 있습니다.
그림 4. 포스트백(Postback) 및 페이지 간 게시
예를 들어 여러 가지 양식으로 구성된 다중 페이지 마법사를 만들 수 있습니다. 최종 유효성 검사가 발생할 수 있는 요약 페이지에 도달할 때까지 각 양식은 순서대로 다음 페이지로 제출됩니다. PreviousPage 개체를 사용하여 현재 컨텍스트에서 마지막 페이지의 데이터에 액세스할 수 있습니다. PreviousPage 개체는 현재 페이지에 사용할 수 있도록 이전 페이지에서 유효성을 검사한 데이터를 저장합니다. 이 개체 덕분에 페이지 간 게시를 사용할 때 컨트롤을 유지할 수 있습니다. 시퀀스에서 양식 한 개를 백업해야 하는 경우 페이지 데이터에 즉시 액세스할 수 있으며 모든 데이터를 다시 입력할 필요가 없습니다.
ASP.NET은 원래 개방형 프레임워크로 디자인되었습니다. 즉, ASP.NET을 구성하는 대부분의 모듈 및 구성 요소를 필요에 맞게 확장, 수정 또는 대체할 수 있습니다. ASP.NET 2.0에서는 이제 프레임워크의 표준이 된 새 HTTPHandlers 및 HTTPModules를 통해 프레임워크의 확장성을 더욱 명확하게 확인할 수 있습니다.
ASP.NET에서 요청은 웹 서버로부터 ISAPI(인터넷 서버 응용 프로그래밍 인터페이스) 필터를 통해 실제 ASP.NET 런타임으로 전달됩니다.
그림 5. 요청 파이프라인
IIS에서 요청을 받으면 IIS 설정에 따라 확장명이 ISAPI 필터에 매핑됩니다. .aspx, .asmx, .asd 등의 확장명은 aspnet_isapi.dll로 매핑됩니다. aspnet_isapi.dll은 ASP.NET 런타임을 시작하는 ISAPI 필터입니다. 요청이 발생하면 ASP.NET 런타임은 ASP.NET 웹 응용 프로그램의 호스트 역할을 하는 HTTPApplication 개체에서 시작됩니다. HTTPApplication 개체는 다음과 같은 동작을 수행합니다.
ASP.NET 2.0에서도 이 모델은 그대로 유지되지만, 다양한 모듈 및 처리기가 새로 추가되어 더 많은 서비스를 제공합니다. ASP.NET 1.x에서와 마찬가지로 모듈 또는 처리기 클래스를 확장, 대체 또는 재구성하여 사용자 지정 기능을 제공할 수 있습니다.
새 HTTPModules가 추가되어 ASP.NET 2.0에서 제공되는 새로운 서비스를 지원합니다. 특히 기본 모듈 설정이 지정된 ASP.NET 응용 프로그램에는 다음에 대한 새 모듈이 포함됩니다.
이러한 새 모듈 외에도, 일부 이전 모듈의 동작이 변경되었습니다. 예를 들어 출력 캐싱 모듈은 이 백서 뒷부분에 설명할 새 캐싱 기술을 지원합니다.
새 모듈 외에도, ASP.NET 2.0에는 응용 프로그램 구성 도구 및 일괄 컴파일 요청 등의 기타 새 기능을 지원하는 처리기가 새로 추가되었습니다. 새 처리기 중 가장 중요한 처리기에는 웹 사이트 관리 요청을 처리하는 ".axd" 패밀리가 있습니다. 이 처리기는 개발자가 ASP.NET 사용자 및 기타 설정을 구성할 수 있도록 하는 내부 관리 도구를 시작합니다. 이러한 관리 처리기는 다음과 같습니다.
일반적인 경우와 같이 HTTPForbiddenHandler는 반환해서는 안 되는 파일 형식에 연결됩니다. ASP.NET 2.0에서는 금지된 파일 형식의 범위가 보다 넓어져서 마스터 페이지, 스킨 파일 및 기타 새 개발자 구성 요소가 포함됩니다.
웹 응용 프로그램의 성능을 향상시킬 수 있는 한 가지 방법은 메모리에서 정적 콘텐츠를 캐시하는 것입니다. 캐시된 콘텐츠는 새로 렌더링된 콘텐츠보다 항상 빠르게 반환됩니다. 하지만 단점은 캐시된 콘텐츠가 오래되어 내용이 부실해질 수 있다는 것입니다. ASP.NET 1.x에서는 다음을 비롯하여 여러 가지 캐싱을 지원합니다.
ASP.NET 2.0에서는 페이지 수준의 캐싱 메커니즘이 확장되어 데이터베이스 종속성을 지원합니다. 데이터베이스 캐시 종속성을 사용하면 캐시된 페이지를 SQL Server 데이터베이스의 특정 테이블에 연결할 수 있습니다. 테이블이 변경되면 캐시가 자동으로 만료됩니다. 또한 개발자는 이제 사후 캐시 대체 기능을 사용하여 캐시된 콘텐츠의 일부를 새로 고친 콘텐츠로 바꿀 수 있습니다. 사후 캐시 대체를 사용하면 페이지의 일부를 동적으로 생성해야 하는 경우에도 응용 프로그램에서 페이지 수준의 캐싱을 사용할 수 있습니다.
대부분의 데이터 기반 웹 사이트에서 캐싱은 어려운 문제일 수 있습니다. 특히 캐싱이 필요한 상황에서 최신 데이터가 필요한 경우에는 더욱 그러합니다. ASP.NET 1.x에서 페이지는 지정한 시간 동안 캐시할 수 있었으며, 입력 매개 변수(쿼리 문자열 또는 POST 매개 변수)에 의해 구성되었습니다.
목록 5. ASP.NET 1.x 출력 캐시 지시문
<%@ outputcache duration="3600" varybyparam="ProdID" %>
예를 들어 목록 5의 코드는 ProdID 변수를 기반으로 한 시간 동안 메모리에서 페이지를 캐시합니다. 위의 예에서 발생하는 문제점은 관련 업무 데이터가 다른 곳에서 업데이트되는 경우 수행해야 하는 작업입니다. 예를 들어 제품 카탈로그 페이지가 제품 ID에 의해 캐시되는 경우를 가정해 봅시다. 가능한 수량이나 가격 등 이 제품에 대한 정보가 관리 사이트에서 업데이트되는 경우 잘못된 데이터가 캐시되어 고객에게 표시됩니다. 이전 버전의 ASP.NET에서 이 문제를 해결하려면 Response.RemoveOutputCacheItem을 사용하여 캐시에서 페이지를 수동으로 제거하거나 duration 시간이 만료될 때까지 기다린 후 시스템에서 자동으로 페이지를 업데이트하도록 해야 했습니다.
ASP.NET 2.0에서는 데이터베이스 캐시 종속성을 지원하므로 이러한 문제가 해결됩니다. SQL Server 7 및 2000에서 작업할 경우 테이블 수준 알림을 사용할 수 있으며, Microsoft SQL Server 2005에서는 보다 세분화된 수준으로 알림을 제공합니다. 예를 들어 다음 코드는 최대 한 시간 동안 제품 페이지를 캐시하지만 데이터베이스 테이블에 두 번째 종속성을 추가합니다.
목록 6. ASP.NET 2.0 데이터베이스 캐시의 예
<%@ outputcache duration="3600" varybyparam="ProdID" sqldependency="MyDatabase:Products" %>
새 sqldependency 특성을 사용하면 Products 테이블이 변경될 경우 캐시된 페이지가 만료됩니다. sqldependency 특성은 web.config 파일에서 구성된 datasource를 참조해야 합니다. datasource는 데이터베이스 연결 및 필요한 매개 변수를 식별하여 종속성 알림 작업을 수행합니다.
ASP.NET 2.0에는 Microsoft SQL Server를 지원하는 단일 CacheDependency 구현인 SQLCacheDependency 클래스가 있습니다. 새 캐시 종속성을 구현하는 작업은 포함된 프로세스이지만, ASP.NET 2.0의 확장성으로 인해 구현이 가능합니다. 즉, 사용자 고유의 CacheDependency 클래스를 만들어 Oracle이나 Sybase 등의 다른 데이터베이스 시스템과 유사한 기능을 제공할 수 있습니다.
일부 페이지 요소는 동적으로 유지되지만 페이지에서 대부분의 요소가 캐시를 사용하는 경우, ASP.NET 2.0에서는 사후 캐시 대체라는 기능을 제공합니다. 사후 캐시 대체는 페이지를 사용자에게 표시하기 전에 캐시된 페이지에 있는 특정 요소를 다시 계산해야 함을 ASP.NET 런타임에 알리는 데 사용됩니다.
다음 두 가지 방법으로 이 기능을 사용할 수 있습니다.
사후 캐시 대체를 인식하는 컨트롤을 만들어 이 기능을 활용할 수 있습니다. 이러한 컨트롤의 예로는 AdRotator 컨트롤을 들 수 있습니다. 목록 7은 다음과 같은 페이지를 나타냅니다.
목록에서 굵게 표시된 <asp:substitution> 컨트롤도 이 예에 추가되었습니다. 이 컨트롤은 문자열 출력(이 경우 현재 시간)을 반환하는 메서드인 uncachedUpdate로 methodname 특성을 설정합니다. 이 대체 컨트롤은 캐시된 대상과 상관없이 정확한 시간을 반환합니다.
목록 7. PostCache.ASPX 소스 코드
<%@ Page language="c#" Codebehind="PostCache.ASPX.cs" AutoEventWireup="true" Inherits="WebApplication1.PostCache" %><%@ outputcache duration="30" varybyparam="none" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ><HTML> <HEAD> <title>WebForm1</title> </HEAD> <body MS_POSITIONING="GridLayout"> <form id="Form1" method="post" runat="server"> <DIV style="DISPLAY: inline; Z-INDEX: 101; LEFT: 32px; WIDTH: 160px; POSITION: absolute; TOP: 24px; HEIGHT: 8px" align="right" ms_positioning="FlowLayout"> this page was created at: </DIV> <asp:Label id="CreatedTime" style="Z-INDEX: 102; LEFT: 200px; POSITION: absolute; TOP: 24px" runat="server" Width="120px" Height="16px"> </asp:Label> <asp:substitution id="UpdatedTime" methodname="uncachedUpdate" style="Z-INDEX: 103; LEFT: 200px; POSITION: absolute; TOP: 48px" runat="server" Width="112px" Height="11px"> </asp:substitution> <DIV style="DISPLAY: inline; Z-INDEX: 104; LEFT: 32px; WIDTH: 160px; POSITION: absolute; TOP: 48px; HEIGHT: 16px" align="right" ms_positioning="FlowLayout"> and last updated at: </DIV> <asp:AdRotator id="Ads" style="Z-INDEX: 105; LEFT: 312px; POSITION: absolute; TOP: 16px" runat="server" Width="80px" Height="60px" AdvertisementFile="img/Ads.xml"> </asp:AdRotator> </form> </body></HTML>
이 페이지의 코드 숨김 파일에는 uncachedUpdate 메서드에서 사후 캐시 대체를 지원하는 데 필요한 이벤트가 포함됩니다. Page_Load 메서드는 페이지를 로드한 시간을 보고하므로 캐싱이 발생하는 시간을 파악할 수 있습니다.
목록 8. PostCache.ASPX.cs
using System;using System.Collections;using System.ComponentModel;using System.Data;using System.Drawing;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;namespace WebApplication1 { public class PostCache : System.Web.UI.Page { protected System.Web.UI.WebControls.Label CreatedTime; protected System.Web.UI.WebControls.Label UpdatedTime; protected System.Web.UI.WebControls.AdRotator Ads; private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } private void Page_Load(object sender, System.EventArgs e) { CreatedTime.Text = DateTime.Now.ToShortTimeString(); } protected String uncachedUpdate() { return DateTime.Now.ToShortTimeString(); } }}
그림 6은 PostCache 페이지의 출력을 보여 줍니다. 응용 프로그램을 처음 실행할 때 "Page created time"과 "Last updated time"이 일치하는 것을 볼 수 있습니다.
그림 6. PostCache.ASPX의 출력
이후에 같은 페이지를 호출하면 사후 캐시 대체의 효과를 확인할 수 있습니다. Page created time과 이미지는 동일하게 유지되지만 Last updated time은 변경됩니다.
그림 7. 두 번째 요청 시 PostCache 출력
캐싱 지시문으로 인해 Page created time과 adRotator 이미지는 일정하게 유지됩니다. 페이지는 30초 동안 캐시됩니다. 이 시간이 지나면 다음 요청 시 Page created time과 adRotator가 업데이트됩니다. 그러나 uncachedUpdate() 메서드를 호출하는 <asp:substitution> 컨트롤은 캐시된 상태와 상관없이 페이지가 요청될 때마다 업데이트됩니다.
사후 캐시 대체를 적절히 사용하면 개발자는 페이지의 동적 부분만 업데이트함으로써 웹 응용 프로그램의 성능을 크게 향상시킬 수 있습니다. ASP.NET 2.0에서 개발한 웹 응용 프로그램을 데이터베이스 캐시 무효화 및 비동기 페이지 업데이트 기능과 함께 사용하면 웹의 일반 요청 및 응답 아키텍처로 인해 발생하는 여러 제한 사항을 없앨 수 있습니다.
ASP.NET 2.0의 인프라 변경 사항 및 추가 기능에 대해 설명했습니다. 그러나 아직 ASP.NET 2.0의 성능에 관한 의문 사항이 남아 있습니다. ASP.NET 2.0이 아직 개발 중이기 때문에 성능 메트릭을 사용할 수는 없지만, ASP.NET 2.0 프레임워크의 모든 면에 걸쳐 성능을 유지하거나 향상시키는 데 많은 노력을 기울여 왔습니다.
모든 개발자가 향상된 성능을 확인할 수 있는 영역은 요청 파이프라인입니다. 많은 이벤트가 새로 추가되었지만, 기본 ASP.NET 요청 스택은 ASP.NET 1.1의 요청 스택보다 최대 30% 빠릅니다. "Hello World"를 표시하는 간단한 페이지를 만들어 향상된 성능을 평가할 수 있습니다. 이 페이지에는 고급 기능이 없기 때문에 ASP.NET 2.0을 IIS에 연결하는 ISAPI 플러그 인을 비롯하여 HTTPHandler 및 HTTPModule 파이프라인을 직접 테스트할 수 있습니다. 보다 빠른 처리를 위해 이 코드가 최적화되었기 때문에 사용 중인 IIS 버전에 상관없이 향상된 성능을 확인할 수 있습니다.
ASP.NET 2.0에서는 IIS 6.0을 함께 사용할 때만 성능이 향상되는 경우가 있습니다. 예를 들어 IIS 6.0의 경우 100명의 사용자가 동시에 여러 개의 컨트롤이 있는 페이지를 요청하는 로드 테스트에서 작업자 프로세스의 작업 집합이 약 50% 감소되었습니다. 이러한 결과는 지정된 서버의 경우 운영 체제에서 이전에 필요했던 리소스에 비해 절반 정도의 리소스만 사용함을 의미합니다.
어느 정도 복잡한 ASP.NET 페이지를 테스트한 결과, 같은 페이지를 IIS 5.0에서 실행했을 때에 비해 시스템 로드(메모리 및 CPU 사용량)가 크게 낮아졌습니다. 이러한 성능 향상은 관리 메모리에서 고유 메모리로 응답 버퍼를 이동함으로써 가능해진 것입니다. ASP.NET 2.0에서는 관리 메모리를 특정 응답에 고정할 필요가 없으므로 리소스 병목 현상이 없으며 각 요청에 대해 응답이 보다 빨리 생성됩니다.
기타 성능 향상은 IIS 6.0과 Windows 운영 체제 커널을 견고하게 통합하여 이룬 것입니다. IIS 6.0에서는 커널 수준에서 일부 캐싱 및 버퍼링을 수행하므로 ASP.NET을 비롯한 모든 웹 응용 프로그램의 성능이 향상됩니다.
개발자는 ASP.NET 2.0의 기능 수행 속도가 ASP.NET 1.x와 같거나 더 빠르다는 것을 알게 될 것입니다. 핵심 기능이 모두 포함된 최종 ASP.NET 2.0 릴리스에서는 더 많은 성능 향상을 확인할 수 있습니다.
ASP.NET 2.0에서는 개발자의 생산성을 높이기 위해 다양한 구조적 기능이 향상되었습니다. 코드 모델이 향상되어 충돌을 줄이고, 컴파일 프로세스가 확장되어 웹 응용 프로그램을 컴파일 및 배포하는 옵션이 보다 다양하게 제공됩니다. ASP.NET 프레임워크의 확장성은 개인 설정, 마스터 페이지, 관리 사이트 등을 비롯하여 ASP.NET의 여러 가지 새 기능을 지원하는 새 HTTPModules 및 HTTPHandlers를 통해 다시 한 번 확인되었습니다. 데이터베이스 종속성과 사후 캐시 대체를 사용할 수 있도록 캐싱이 향상되었습니다. 내부적으로 ASP.NET 2.0에는 이전 버전에 비해 크게 향상된 기능이 포함되어 있습니다. ASP.NET 2.0의 새로운 구현 방식은 업계 최고의 방식을 따르는 동시에 다양한 개발자 중심의 향상된 기능을 통합합니다. ASP.NET 2.0에서는 복잡한 엔터프라이즈 웹 응용 프로그램 개발 작업을 처리할 수 있는 세계 최고의 웹 개발 플랫폼을 제공합니다.
[펌] ASP.NET 기본 제공 기능을 활용하여 웹 공격 차단 (0) | 2006.02.09 |
---|---|
[펌] [ASP.NET] ASP.NET 2.0의 마스터 페이지 (0) | 2006.01.17 |
VS2005 에서 aspx 파일 생성할때 XHTML 문법 체크때문에 ㅎㅎ (0) | 2006.01.16 |
NET Framework V2.0 Obsolete API List (0) | 2006.01.13 |
ibatis.com... 닷넷용두 있었네.. ㅋ (0) | 2005.06.03 |
기본 설정을 어케 바꾸는지 몰라서..
aspx 파일 하나 생성하구... DOCTYPE 을 바꿔준다는 ㅎㅎㅎ
하여간에 비쥬얼 스튜디오에서 웹폼 생성하면 HTML 부분이 이렇게 아래처럼 된다...
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
여기서 DOCTYPE 이랑 HTML 부분을 4.0 스타일로 바꿔야
vs 에서 문법 체크를 안한다...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
...
이렇게 말이다.. 흐흐
[펌] ASP.NET 기본 제공 기능을 활용하여 웹 공격 차단 (0) | 2006.02.09 |
---|---|
[펌] [ASP.NET] ASP.NET 2.0의 마스터 페이지 (0) | 2006.01.17 |
[펌] ASP.NET 2.0 내부 변경 사항 (0) | 2006.01.16 |
NET Framework V2.0 Obsolete API List (0) | 2006.01.13 |
ibatis.com... 닷넷용두 있었네.. ㅋ (0) | 2005.06.03 |