저자: 한동훈(traxacun)
[지난기사보기]
•
ASP.NET 가이드 3. UI 향상 및 사용자 템플릿 만들기
•
ASP.NET 가이드 2. 숫자/문자 입력 텍스트 박스 만들기
•
ASP.NET 가이드 1. 자바 스크립트 사용하기
이번회에서는 통합 예외처리에 대해 살펴볼 것이다.
자바스크립트를 추가하고, 그 기능들을 컨트롤에 어떻게 연관시키는지를 3회에 걸쳐서 살펴보았기 때문에 앞으로 소개할 코드들도 자세히 설명하지 않아도 이해할 수 있을 것이다. 게다가 자바스크립트에 대해 설명할 밑천도 떨어졌으니 슬슬 다른 주제로 바꿀때가 된 것도 같다. ^^;
통합 예외처리에 대해 살펴볼 것이다. ASP.NET에서 제공하는 예외 처리 방법들에 대해서 살펴보고, 프로젝트가 몇 개인가에 관계없이 통합 예외처리를 하기 위해 BasePage 클래스를 확장하는 것을 살펴볼 것이다.
1. 통합 예외처리
1.1 ASP.NET 예외 처리의 종류
- 응용 프로그램 단위 예외 처리
가장 흔하게 생각할 수 있는 방법이 응용 프로그램 단위로 예외를 처리하는 방법이다. 이 방법은 web.config의 customErrors 섹션을 설정해서 처리한다. 그림1은 에러가 발생했을 때 Error.htm을 보여주는 것이고, 자신의 PC에서 테스트하는 사람도 사용자와 동일한 화면을 보기 위해 mode="on"으로 설정하였다.
그림1. web.config의 customErrors 섹션 설정
어떤 오류가 발생했을 때 사용자에게 보여주는 화면은 일반 HTML 파일로 작성했다. 만약, 오류 페이지를 ASPX 페이지로 작성했다고 하자. ASP.NET 런타임에 문제가 생긴 경우 다른 HTML 파일이나 이미지는 잘 볼 수 있지만 모든 ASPX 페이지는 볼 수 없는 문제가 생긴다. 이런 경우 ASPX 페이지로 작성한 예외 페이지는 무용지물이기 때문에 예외 페이지는 HTML로 작성하는 것이 좋다.
다음은 예외가 발생했을 때 보여줄 Error.htm 파일의 디자인이다.
그림2. 오류 페이지
web.config의 설정을 변경한 것과 error.htm을 추가한 것이 어떻게 동작하는지 알아보기 위해 간단한 테스트 페이지(MissingLink.aspx)를 작성하였다.
그림3. MissingLink.aspx 페이지
그림3에서 볼 수 있는 것처럼 실제로 작성한 적이 없는 Missing.aspx 페이지로 링크를 만들었다. MissingLink.aspx 페이지를 실행하고 링크를 클릭하면 다음과 같은 화면을 볼 수 있다.
그림4. 응용 프로그램 오류 화면
많은 웹 개발자가 알고 있는 것처럼 HTTP 상태코드1)에 따른 오류 페이지를 지정할 수 있다. 페이지를 찾을 수 없는 경우 HTTP 상태코드는 404이며, 이 경우에만 보여줄 오류 페이지를 지정하려면 web.config를 다음과 같이 수정하고 적절한 예외 페이지를 작성하면 된다.
그림5. 401, 404에 대한 오류 페이지 설정
Error404.htm 페이지를 작성하고 MissingLink.aspx 페이지를 테스트하면 Error.htm의 내용 대신 Error404.htm의 내용이 표시되는 것을 확인할 수 있다. 위에는 401, 404에 대해서는 지정된 페이지를 보여주고, 그외의 오류에 대해서는 Error.htm 페이지를 보여주도록 설정한 것이다.
web.config를 이용한 설정은 위에서 살펴본 것처럼 해당 프로젝트에 속한 모든 ASPX 페이지에 적용된다.
- 페이지 단위 예외 처리
페이지 단위 예외 처리는 페이지별로 예외를 처리하는 것이다. ASPX 페이지의 Page 지시자에 ErrorPage를 지정하는 방법이다.
그림6. ErrorPage 속성 사용
- Global.asax의 예외 처리
Global.asax.cs에 보면 Application_Error 메서드가 있습니다. 여기에 예외 처리 코드를 추가할 수 있지만 web.config 설정을 이용한 방법에 비하면 문제를 세세하게 제어하지 못한다.
1.2 ASP.NET 예외 처리의 문제점
앞서 소개한 ASP.NET의 예외 처리 방법은 프로젝트나 응용 프로그램 하나에만 적용되는 방법이다. 그러나, 실제로 회사에서 개발을 하는 경우 한 사람이 모든 개발을 하는 것이 아니며, 응용 프로그램도 각 기능별로 작은 프로젝트로 분업하는 것이 보통이다.
- 페이지 기반 예외 처리의 문제점
페이지 기반 예외 처리는 모든 ASPX 페이지의 @PAGE 지시문에 ErrorPage 속성을 지정해야 한다. 3회에서 소개한 비주얼 스튜디오 템플릿을 개발한다해도 ErrorPage의 URL이나 페이지 이름 변경과 같은 경우에 대해 능동적으로 대처할 수 없다. 템플릿에 추가하는 것은 임시방편이지 확실한 해결책은 아니다.
- 응용 프로그램 단위 예외 처리의 문제점
응용 프로그램 단위 예외 처리는 상당히 좋은 방법이지만, 실제로 포탈 사이트, 사내 업무용 사이트는 응용 프로그램 하나로 구성된 것이 아니라 다양한 응용 프로그램으로 구성되어있다. 가령, 뉴스, 이메일, 공지사항, 업무 연락사항, 업체 관리, 계약 정보 관리와 같은 다양한 응용 프로그램들이 한데 엮여서 하나의 사이트를 이룬다.
따라서, 각 응용 프로그램마다, 또는 해당 응용 프로그램을 세세하게 나눈 프로젝트 수만큼 동일한 설정 작업을 반복해야 한다.
1.3 통합 예외처리
통합 예외처리를 위해 사용할 수 있는 방법은 IHttpModule, IHttpHandler를 직접 구현하여 웹 모듈을 직접 제작하는 방법이 있지만, 필자의 경우엔 BasePage에 예외 처리를 확장하여 이용한다.
BasePage 클래스는 System.Web.UI.Page 클래스를 상속받는다. 즉, Page 클래스의 모든 기능을 갖고 있다는 것을 의미한다. Page 클래스는 예외가 발생했을 때 처리할 이벤트 핸들러를 Page.Error에 지정할 수 있다.
일반적인 ASPX 페이지 개발은 System.Web.UI.Page 클래스를 상속하기 때문에 모든 ASPX 페이지에 Page.Error 이벤트 핸들러를 추가해야하지만, BasePage 클래스를 이용하는 방법은 BasePage에 한번만 Page.Error 이벤트 핸들러를 추가하고 이를 재상속하여 ASPX 페이지를 개발한다.
예외 처리의 변경사항이 발생하면 BasePage 클래스만 수정하는 것으로 BasePage 클래스를 사용하는 모든 프로젝트, 모든 ASPX 페이지에 변경사항이 적용된다. 모듈을 이용한다면 모든 프로젝트의 web.config를 수정하지만 BasePage 클래스를 이용하는 방법은 그런 작업조차 없기 때문에 단순반복작업을 제거할 수 있다.
- 통합 예외처리를 위한 BasePage 확장하기
BasePage의 이벤트 등록은 모두 OnInit에서 하기 때문에 Error 이벤트 핸들러로 이곳에 등록한다.
그림7. BasePage_Error 이벤트 핸들러 지정
위와 같이 이벤트 핸들러를 지정했으면 Error 이벤트가 발생할 때 실행할 BasePage_Error를 구현해보자.
먼저, Server 객체에 대해서 알아야 한다. Server 객체는 Page.Server 속성을 의미하며, 실제로는 HttpServerUtility 클래스이다. 이 클래스에서 에러처리와 관련해서 자주 쓰이는 메서드로는 GetLastError()와 ClearError()가 있다.
Server.GetLastError()는 마지막으로 발생한 예외를 가져오며 반환형식은 System.Exception 클래스다. Server.ClearError()는 스택에 저장된 예외를 모두 삭제하는 역할을 한다.
그림8. BasePage_Error()
첫번째는 예외가 발생했을 때 해당 예외를 가져오기 위한 것이며, DEBUG 모드로 컴파일되는 경우에는 개발자에게 예외를 보여주기 위해 위와 같이 예외를 화면에 출력하는 코드를 추가하였다. 위와 같은 예외 처리를 직접 정의하게 되면 ASP.NET 응용 프로그램을 개발할 때 보게되는 에러 화면을 전혀 볼 수 없게 때문에 위와 같이 직접 그 정보를 화면에 보여주는 코드를 작성해야 한다.
세번째는 RELEASE 모드 즉, 최종 버전으로 개발된 제품의 경우 에러가 발생했을 때 사용자에게 에러 대신 에러 페이지를 보여주기 위한 부분이다. 여기서는 에러를 기록하는 LogEvent()를 사용하고 있는데, 이는 직접 작성한 함수이며, 이벤트 로그에 기록한다.
두 상자안에 코드의 색상이 전혀 다르게 나타나는데, 이는 VS.NET에서 현재 개발 모드가 DEBUG, RELEASE에 따라 다르게 나타난다.
여기서는 발생하는 예외를 이벤트 로그에 기록하는 방법을 선택했다.
그림9. LogEvent()
.NET에서는 이벤트 로그를 쉽게 사용할 수 있는 EventLog 클래스를 제공한다. EventLog.SourceExists로 해당 카테고리가 있는지 확인하고, EventLog.CreateEventSource로 이벤트 로그에 해당 이름을 작성한다. EventLog.WriteEntry는 이벤트 로그에 내용을 기록한다.
EventLog 클래스를 사용하기 위해서는 using System.Diagnostics;를 선언에 추가해야한다.
위와 같이 이벤트 로그는 레지스트리를 이용해서 관리한다. 웹을 이용하는 사용자는 서버의 레지스트리를 변경할 수 있는 권한이 없기 때문에 해당하는 키가 없는 경우 EventLog.CreateEventSource()는 에러가 발생하게 된다. 따라서, 레지스트리에 EventLogCategory 변수에 지정된 이름을 키로 미리 등록해주서야 한다.
- 레지스트리 오류 해결방법
레지스트리에 다음과 같은 키를 추가해주면 "Registry access not allowed." 에러가 발생하는 것을 해결할 수 있다.
HKLM/SYSTEM/CurrentControlSet/Services/EventLog/Application/MonaC
항목을 생성한다.
참고자료
1. HTTP 상태코드
RFC 2616에 정의된 상태 코드는 스펙이기 때문에 장황한 감이 있으니 다른 사이트에 간략하게 정리된 것을 이용하면 좋겠다. 첫번째는 간략하게 정리된 것이고, 두번째는 RFC 2616의 상태 코드이다.