Programmer/Ajax - 해당되는 글 2건
목차
Atlas란?
Atlas 아키텍처
클라이언트 스크립트 핵심 라이브러리
클라이언트 스크립트 컨트롤과 구성 요소
서버 컨트롤
웹 서비스
결론


2005년 9월, ASP.NET 팀은 "Atlas"라는 코드명의 ASP.NET에 도입된 새 기능에 대한 첫 CTP(Community Technology Preview) 버전을 발표했습니다.

Microsoft .NET Framework 2.0에 적용되는 이 확장 기능을 사용하여 개발자는 브라우저와 서버의 기능을 모두 활용하여 풍부한 기능의 대화형 웹 사이트를 보다 쉽게 만들 수 있습니다.

Atlas에서 제공하는 풍부한 개발 환경을 흔히 AJAX(Asynchronous JavaScript and XML)라고 하며, 이는 그 동안 사용된 여러 가지 기술의 이름을 결합하여 만든 비교적 새로운 머리글자어입니다. 요즘에 사용되는 브라우저에는 JavaScript에서 서버를 호출하는 데 사용할 수 있는 XMLHttpRequest 개체가 포함되어 있는데, 이 개체를 사용하면 웹 페이지에서 사용자가 입력한 내용에 반응하여 전체 페이지를 새로 고치지 않고도 대역 외 작업을 수행할 수 있습니다. 이 개념 자체는 단순하지만 AJAX 라이브러리는 서버와 통신하고 웹 서비스에서 반환되는 XML을 처리하기 위해 클라이언트 쪽 JavaScript를 작성해야 하는 고된 작업을 크게 줄여줄 수 있습니다.

AJAX를 통해 해결하려는 일반적인 문제들은 대개 HTTP 프로토콜 자체의 특성에서 비롯됩니다. HTTP는 브라우저가 웹 서버와 통신하여 웹 페이지를 가져오고 데이터를 웹 서버에서 받아 다시 게시하기 위해 사용하는 표준 프로토콜로서, 상태를 저장하지 않는 방식의 프로토콜이므로 페이지를 새로 고치기 전에는 사용자의 입력이 서버의 코드에 전달되지 않습니다. 따라서 일반적인 사용자 환경에서는 상태 정보를 서버로 보내기 위해 전체 페이지를 새로 고쳐야 합니다. 사용자가 페이지에 입력한 내용은 서버에서 처리된 후 HTML 형식으로 복원되어 브라우저로 다시 보내집니다.

ASP.NET에서는 이러한 프로세스를 화면에 보이지 않는 폼 필드를 사용하여 관리합니다. 페이지의 일부만 업데이트되더라도 전체 페이지의 HTML이 전송되므로 브라우저 화면은 일시적으로 비어 있게 됩니다. 또한 페이지의 내용을 새로 고치기 위해 브라우저에서 새 내용을 받아 렌더링하는 동안에는 사용자가 웹 페이지와 상호 작용할 수 없습니다. AJAX는 이러한 환경을 개선하기 위해 전체 페이지를 새로 고치지 않고도 서버를 호출하여 웹 서비스를 실행할 수 있는 XMLHttpRequest 개체를 사용합니다. 이 개체를 사용하면 수신한 XML을 기반으로 페이지의 업데이트할 부분을 JavaScript에서 직접 수정할 수 있습니다. 사용자는 페이지가 업데이트되고 있는지 알아챌 수 없으며, 작업은 대역 외 방식으로 백그라운드에서 비동기로 실행되므로 그 동안에도 계속해서 웹 페이지를 읽거나 상호 작용할 수 있습니다.


Atlas란?

ASP.NET의 Atlas 기능을 단지 클라이언트 중심의 웹 응용 프로그램을 만들기 위한 또 하나의 AJAX 스크립트 라이브러리로 생각해서는 안 됩니다. Atlas는 .NET Framework 2.0을 기반으로 만들어졌으며 클라이언트 쪽 JavaScript와 XMLHttpRequest 개체의 기능을 보다 잘 활용할 수 있도록 지원합니다. 또한 기존 ASP.NET 응용 프로그램뿐 아니라 Atlas 컨트롤과 서비스에서 사용하는 클라이언트 스크립트 라이브러리도 손쉽게 향상시킬 수 있는 서버 기반 기능을 갖추고 있습니다. 그림 1의 Atlas 아키텍처 다이어그램은 Atlas가 클라이언트와 서버 모두를 확장하며, 기능이 더욱 다양하고 응답이 보다 빠른 브라우저 간 웹 응용 프로그램을 만들 수 있는 광범위한 개발 기술로 간주되어야 함을 보여 줍니다.

그림 1 ASP.NET Atlas 아키텍처
그림 1 ASP.NET Atlas 아키텍처

Atlas를 활용할 수 있는 시나리오는 JavaScript를 비동기식으로 호출하여 웹 페이지의 일부를 업데이트하는 것에 한정되지 않으며 그 동안 구현하기 힘들었던 다양한 클라이언트 환경을 만드는 데 사용할 수 있습니다. 예를 들어 영화 관련 데이터로 구성된 웹 응용 프로그램이 있다고 가정해 보겠습니다. 사용자가 이 응용 프로그램을 사용하여 특정 배우를 검색할 수도 있습니다. 모든 배우 이름을 하나의 드롭다운 목록으로 만들어 제공하는 것은 비현실적이므로 선택의 폭을 좁힐 수 있는 다른 방법을 찾아야 합니다. 예를 들어 배우 이름의 첫 번째 글자를 선택하도록 사용자에게 요청하고 이 글자로 서버에 요청하여 해당 글자가 포함된 목록을 제공하면 처리가 보다 수월해지지만 사용자 입장에서는 귀찮은 일이 됩니다. 또 다른 방법으로, 배우의 이름 중 일부만 입력하여 검색할 수 있는 입력란을 제공할 수도 있습니다. 그러면 서버에서 사용자가 입력한 데이터를 기준으로 검색의 범위를 좁힐 수 있을 것입니다. 첫 번째 방법보다는 낫지만, 이 방법 역시 여전히 개선의 여지가 있습니다. Atlas를 사용하면 사용자의 입력에 따라 동적으로 반응하는 입력란을 제공하여 브라우저에서 전체 페이지를 새로 고칠 때까지 기다리지 않고도 검색 범위를 좁힐 수 있습니다. 그림 2는 Atlas를 사용하여 사용자의 입력에 따라 피드백을 제공하는 자동 완성 동작을 추가한 모습을 보여 줍니다.

그림 2 필터링 콤보 상자
그림 2 필터링 콤보 상자

Atlas CTP는 atlas.asp.net (영문)에서 다운로드할 수 있습니다. Atlas CTP를 설치하면 C# .NET 및 Visual Basic .NET용 추가 웹 사이트 템플릿이 Microsoft Visual Web Developer™에 추가되므로 Visual Web Developer에서 파일, 새로 만들기, 웹 사이트를 차례로 클릭하여 웹 사이트 프로젝트를 새로 만들 때 그림 3과 같은 대화 상자가 표시됩니다. Atlas 기반의 ASP.NET 기능을 사용하기 위해, Atlas 웹 사이트에는 웹 응용 프로그램을 구성하는 업데이트된 web.config 파일과 Microsoft.Web.Atlas.dll이 포함됩니다. 현재 릴리스의 경우 Microsoft.Web.Atlas.dll은 응용 프로그램 전체에서 사용할 수 있는 로컬 어셈블리로 응용 프로그램의 bin 디렉터리에 배치됩니다.

그림 3 Atlas 웹 사이트 만들기
그림 3 Atlas 웹 사이트 만들기

Atlas 기반 응용 프로그램은 Atlas를 별도로 설치할 필요 없이 개발 컴퓨터에 있는 파일을 ASP.NET 2.0이 있는 서버로 복사하여 쉽게 배포할 수 있습니다. Atlas는 시스템 수준이 아니라 응용 프로그램 수준에서 설치되므로 다음 버전의 CTP가 제공되면서 기능이 발전하고 변경될 경우 이전 버전의 Atlas가 있는 컴퓨터에서 새 버전을 사용할 수 있습니다. 따라서 시스템 수준으로 설치하는 경우보다 더욱 유연하게 마이그레이션할 수 있습니다.



페이지 맨 위로페이지 맨 위로


Atlas 아키텍처

그림 1의 Atlas 아키텍처 다이어그램에서 가장 먼저 주목해야 할 사실은 Atlas가 클라이언트와 서버 양쪽 모두에 적용된다는 점입니다. ASP.NET 2.0에 몇 가지 클라이언트 기능이 추가되었지만 이는 Atlas의 적용 범위에 미치지 못합니다. 아키텍처 다이어그램의 오른쪽을 보면 Atlas의 서버 기능이 ASP.NET 2.0을 기반으로 이를 확장하고 있음을 알 수 있습니다. Atlas는 브라우저에서 서버 기반 데이터와 서비스에 액세스할 수 있는 새로운 기능뿐만 아니라 새로운 서버 컨트롤 집합도 제공합니다.

다이어그램 왼쪽에는 서버 기능과는 별도로

그림 4 일반적인 클라이언트-서버 상호 작용
그림 4 일반적인 클라이언트-서버 상호 작용
클라이언트 중심의 JavaScript를 만들 때 사용할 수 있는 포괄적인 클라이언트 스크립트 라이브러리가 나와 있습니다. 이 라이브러리는 향상된 클라이언트-서버 상호 작용이 가능한 풍부한 기능의 응용 프로그램을 개발하기 위해 새 Atlas 기능에서 많이 사용하는 클라이언트의 기반 구조라 할 수 있습니다.

그림 4는 웹 응용 프로그램의 일반적인 클라이언트-서버 상호 작용 방식을 보여 줍니다. 먼저 브라우저에서 웹 페이지를 요청하고 사용자는 이 페이지와 상호 작용합니다. 사용자의 작업을 위해 서버의 데이터가 필요하면 전체 페이지가 새로 고쳐지며

그림 5 Atlas의 클라이언트-서버 상호 작용
그림 5 Atlas의 클라이언트-서버 상호 작용
사용자 입력에 따라 페이지의 일부를 업데이트합니다. 그러나 이 방식에서는 페이지가 업데이트되는 동안 사용자가 페이지와의 상호 작용을 계속할 수 없습니다. 즉, 사용자는 웹 응용 프로그램에서 작업하는 동안 계속해서 작업을 일시 중단해야 합니다.

그림 4 일반적인 클라이언트-서버 상호 작용그림 5는 전체 페이지를 새로 고칠 필요가 없는 Atlas의 클라이언트-서버 상호 작용 방식을 보여 줍니다. 이 방식에서는 처음 HTML을 가져온 후 서버를 다시 호출할 경우 XML, JSON(JavaScript Object Notation) 또는 HTML 조각으로 업데이트된 데이터를 가져와 페이지를 증분 업데이트합니다. 웹 서비스를 호출하거나 페이지 변경 내용을 가져오기 위한 호출이 비동기식으로 백그라운드에서 수행되므로 사용자는 작업을 일시 중단할 필요가 없습니다. 이러한 비동기식 호출에서는 서버로의 다음 번 다시 게시 작업을 위해 업데이트된 보기 상태 정보를 관리하므로 페이지를 완전히 새로 고쳐야 할 경우 페이지의 정확한 상태를 서버에 전달합니다.



페이지 맨 위로페이지 맨 위로


클라이언트 스크립트 핵심 라이브러리

Atlas의 클라이언트 스크립트 라이브러리는 분리된 몇 개의 고유한 조각으로 브라우저에 전달됩니다. 스크립트 핵심은 나머지 라이브러리의 기반이 되는 하위 계층을 구성하며 최하단에는 브라우저 호환성 계층이 자리잡게 됩니다. Atlas의 주요 특징은 AJAX의 주요 요소를 지원하는 최신 브라우저에서만 Atlas가 실행된다는 점입니다. CTP 빌드를 지원하는 브라우저로는 Mozilla Firefox, Apple Safari 및 Microsoft Internet Explorer가 있습니다. 브라우저 호환성 계층은 브라우저의 차이에 신경 쓰지 않고 보다 편리하게 스크립트를 작성할 수 있게 해 주는 추상화 계층입니다. 이 계층을 통해 브라우저의 구현 방식에 의한 차이는 감춰지며 브라우저의 업데이트나 새 버전 발표에 맞춰 Atlas 지원도 쉽게 확장될 수 있습니다. 요청하는 브라우저의 종류에 따라 호환성 계층의 브라우저별 부분 중 어떤 부분이 사용될지 자동으로 결정되며 추상화 계층에 상위 수준의 코드가 미리 작성되어 있으므로 브라우저 구현에 따라 다르게 코딩할 필요가 없습니다.

호환성 계층의 최상단에는 핵심 형식 시스템이 있습니다. 형식 시스템은 JavaScript에서 개체 지향 방식을 사용하기 위한 것으로, JavaScript 개발자는 이 시스템을 사용하여 네임스페이스를 만들고 이 네임스페이스에 클래스를 추가할 수 있으며 개체 상속도 시뮬레이트할 수 있습니다. 또한 인터페이스, 대리자, 열거형을 지원하므로 C# 같은 개체 지향 프로그래밍 언어를 사용하는 서버에서의 코드 개발과 JavaScript를 사용하는 클라이언트 코드 작성 간의 전환이 수월합니다.

형식 시스템을 기반으로 구축된 기본 클래스 라이브러리 계층은 클라이언트 스크립트 라이브러리의 핵심을 완성합니다. 개념 자체가 .NET Framework를 모방한 것이므로 일부 형식은 이미 사용자에게 친숙할 것입니다. 예를 들어 JavaScript에서 자연스럽게 이벤트를 멀티캐스팅할 수 있도록 지원하는 Event 개체가 있으며 StringBuilder 개체도 있습니다. 또한 JSON과 XML 데이터에 대한 지원뿐 아니라 개체의 직렬화(serialization)도 지원합니다. 기본 클래스 라이브러리에는 브라우저의 XMLHttpRequest 개체에 대한 추상화를 제공하는 WebRequest와 WebResponse 클래스도 있습니다. 이는 .NET Framework의 System.Net 네임스페이스에 있는 개체와 상당히 유사합니다. 그림 6의 코드는 Atlas 스크립트 핵심을 사용하여 JavaScript로 두 개의 간단한 형식을 만드는 방법을 보여 줍니다. 첫 번째 형식인 Movie는 영화의 제목과 장르를 보여주는 두 속성, 그리고 결과를 문자열로 반환하는 toString 메서드를 지원합니다. 두 번째 형식인 Drama는 Movie 형식을 확장하고 toString 메서드를 다시 정의합니다.

Movie와 Drama 형식을 사용하는 페이지는 그림 7에서 볼 수 있습니다. 이 페이지는 먼저 형식이 정의되어 있는 .js 파일을 참조합니다. 이 파일은 Atlas ScriptManager 컨트롤에 포함되어 있습니다. 그런 다음 Click 처리기에서 Movie와 Drama 형식의 인스턴스를 만들고 이 인스턴스의 toString 메서드를 호출합니다. 사용되는 코드는 동적 JavaScript이지만 상속 동작은 개체 지향 프로그래밍 언어를 사용할 때와 동일합니다. 현재 발표된 Atlas의 또 다른 장점은 클라이언트 스크립트 라이브러리의 디버그 버전이 포함되어 디버깅과 문제 해결이 더 쉽다는 것입니다. JavaScript 디버깅은 항상 번거로운 작업이었으므로 이러한 지원은 많은 수고를 덜어줄 수 있습니다.



페이지 맨 위로페이지 맨 위로


클라이언트 스크립트 컨트롤과 구성 요소

AppDomain은 관리 코드의 하위 프로세스를 격리합니다. 이것은 각 AppDomain에 고유의 상태 집합이 있다는 의미입니다. 하나의 AppDomain에 있는 확인할 수 있는 코드는 호스팅 환경에서 작성된 인터페이스가 상호 작용을 허용하지 않는한 다른 AppDomain에 있는 코드나 데이터를 손상시키지 않습니다. 이것이 어떤 방식으로 작동하는지 알아 봅시다. C# 및 Visual Basic .NET 컴파일러에서 기본적으로 작성되는 형식이 안전한 확인할 수 있는 코드는 어떤 방법으로도 메모리에 액세스할 수 없습니다. 각 명령은 형식이 안전한 방식으로 메모리에 액세스하도록 확인 규칙 집합을 사용하여 런타임으로 검사됩니다. 따라서 런타임 검사을 통해 확인할 수 있는 코드를 실행할 때 AppDomain의 격리를 보장하며 확인할 수 없는 코드의 실행을 막을 수 잇습니다.

호스트는 이러한 격리를 통해 코드를 동일한 프로세스에서 다른 신뢰 수준으로 안전하게 실행할 수 있습니다. 낮은 신뢰 코드는 신뢰할 수 있는 호스트 코드 또는 다른 낮은 신뢰 코드와는 별도로 AppDomain에서 실행할 수 있습니다. 낮은 신뢰 코드의 호스트에 필요한 AppDomain 수는 해당 호스트의 격리 의미에 따라 다릅니다. 예를 들어 Internet Explorer는 관리 컨트롤에 대해 사이트당 하나의 AppDomain을 작성합니다. 한 사이트의 컨트롤은 동일한 AppDomain에서 상호 작용할 수 있지만 다른 사이트의 컨트롤을 간섭하거나 악의적으로 이용할 수 없습니다.

Atlas 아키텍처의 클라이언트 스크립트 핵심을 구성하는 계층 위에는 구성 요소 모델과 컨트롤 계층이 있습니다. 스크립트 라이브러리의 이 계층은 하부의 스크립트 핵심을 기반으로 구축되지만 클라이언트에서는 별도로 렌더링됩니다. 스크립트를 작성할 때 구성 요소 계층을 포함하지 않고 JavaScript 형식 시스템과 기본 클래스 라이브러리를 직접 사용할 수도 있지만, 이렇게 하면 Atlas에서 제공되는 클라이언트 구성 요소에 액세스할 수 없으며 브라우저로 보내지는 페이지 마크업에 포함되는 새로운 선언적 요소 집합인 xml-script를 사용할 수 없게 됩니다. xml-script 요소는 다음과 같은 새로운 형식 값을 사용하는 스크립트 태그 안에 포함됩니다.

<script type="text/xml-script">

마크업에서 추가적인 요소 집합을 사용하기 위한 가장 기본적인 방법은 스크립트 태그를 사용하는 것입니다. 브라우저는 스크립트 요소를 인식하지만 text/xml-script 형식을 처리할 수는 없습니다. 스크립트 태그 자체에 포함된 요소는 Atlas 스크립트 라이브러리에서 처리될 수 있으며 마크업은 클라이언트 스크립트 라이브러리의 구성 요소 계층에서 처리됩니다. xml-script는 클라이언트에서 구문 분석되어 구성 요소와 컨트롤의 인스턴스를 만듭니다. xml-script에는 정의하는 구성 요소와 컨트롤에 대한 속성 설정이 포함될 수 있으며 페이지의 다른 부분에 있는 HTML 요소와의 바인딩도 선언될 수 있습니다. 또한 xml-script 요소에서 웹 서비스 리소스를 선언한 다음 마크업의 다른 부분에서 이를 데이터 소스로 참조할 수도 있습니다. 그림 8의 예제 페이지는 xml-script를 사용하여 마우스 포인터로 연도를 가리킬 때 해당 연도와 관련된 영화 제목이 팝업 요소로 표시되도록 선언적으로 설정하고 있습니다.

그림 8의 페이지에서는 연도를 표시하기 위해 DIV 요소를, 영화 제목을 표시하기 위해 SPAN 요소를 사용하지만 숨겨지도록 선언했습니다. xml-script의 popupBehavior는 영화 제목과 연결되어 있으며 해당 연도와 연결된 hoverBehavior에 의해 실행됩니다. popupBehavior에 대한 코드는 Atlas 스크립트 라이브러리의 컨트롤과 구성 요소 계층에 있습니다. xml-script는 일반적으로 페이지에 포함되는 JavaScript에 비해 더 쉽게 분석할 수 있으며, 특히 다수의 브라우저 구현을 처리하기 위해 코드에서 팩터링을 시작할 때 이러한 특징이 두드러지게 나타납니다. 그림 8의 xml-script와 같은 선언적 구문은 개발 도구를 사용하여 쉽게 만들고 사용할 수 있으며 풍부한 기능의 사용자 환경을 가능하게 하는 xml-script는 페이지가 실행될 때 Atlas 서버 컨트롤에 의해 만들어집니다. Atlas 응용 프로그램에서 사용되는 대다수의 xml-script는 .aspx 파일에 전혀 존재하지 않으며 개발자가 직접 코딩할 필요도 거의 없습니다.

Atlas CTP에서 제공하는 다양한 동작은 사용자 환경을 개선하는 데 사용됩니다. 진행률 동작은 백그라운드에 보류되어 있는 작업에 대한 정보를 제공할 수 있으며 클릭, 가리키기, 팝업 동작은 다양한 사용자 상호 작용을 가능하게 합니다. 이러한 동작은 xml-script를 사용하여 선언적 방식으로 페이지의 HTML 요소와 쉽게 연결할 수 있습니다. 동작 자체는 JavaScript로 구현되기 때문에 더 복잡한 동작도 가능하지만, 페이지에서 동작을 사용할 때는 xml-script를 사용할 수 있습니다.



페이지 맨 위로페이지 맨 위로


서버 컨트롤

Atlas CTP에 포함된 서버 컨트롤을 사용하면 페이지를 다시 게시할 때 일시적으로 상호 작용이 중단되는 것을 방지할 수 있습니다. 즉, 서버 컨트롤이 백그라운드에서 렌더링을 업데이트하는 동안 사용자는 웹 페이지와 계속 상호 작용할 수 있습니다. 이러한 기능의 주역은 함께 작동하는 두 개의 서버 컨트롤입니다. 이러한 두 서버 컨트롤을 기존 페이지에 추가하면 상당한 기능 향상을 얻을 수 있습니다. 첫 번째 컨트롤인 ScriptManager 컨트롤은 클라이언트에서 서버로의 다시 게시 동작을 변경하며 두 번째 컨트롤인 UpdatePanel 컨트롤은 변경 작업을 위해 서버에서 페이지의 수명 주기를 관리합니다.

ScriptManager 컨트롤은 Atlas 기능을 사용할 모든 페이지에 포함되어야 합니다. 이 컨트롤은 클라이언트로 보내는 JavaScript를 제어하는 역할을 하는데, 서버 컨트롤은 클라이언트에 JavaScript를 제공할 수 있으며 이 동작을 제어하기 위해 ScriptManager 컨트롤을 이용합니다. ScriptManager 컨트롤은 구현을 위해 새로운 IScriptComponent 인터페이스를 이용하며 xml-script 요소와 연결되는 구성 요소 스크립트 라이브러리도 지원합니다.

다음과 같이 ScriptManager 컨트롤의 EnablePartialRendering 속성을 true로 설정하면 클라이언트에서 서버로의 다시 게시 동작이 새롭게 변경됩니다.

<atlas:ScriptManager EnablePartialRendering="true" runat="server" />

이 코드를 통해 사용자 환경을 중단하지 않고도 서버로 다시 게시를 요청할 수 있게 됩니다. 요청 간의 제어 정보를 보존하는 데 필요한 보기 상태 정보는 부분적 렌더링 요청을 위해 유지됩니다. 그리고 새로 고쳐지거나 수정되는 부분에 대한 HTML은 브라우저 DOM(Document Object Model)과 상호 작용하는 JavaScript에서 업데이트됩니다. ASP.NET 페이지에서 부분 업데이트를 허용해야 하는 영역은 UpdatePanel 컨트롤을 사용하여 지정됩니다.

UpdatePanel 컨트롤은 페이지의 나머지 부분과는 별개로 업데이트되어야 하는 영역을 ScriptManager 컨트롤에 알리는 역할을 합니다. 사용자가 브라우저에서 수행한 작업으로 인해 페이지의 일부를 다시 게시해야 할 경우, 폼 데이터가 게시되고 페이지 수명 주기가 서버에서 실행되기 시작합니다. 이때 스크립트는 백그라운드에서 비동기식으로 다시 게시 작업을 초기화하므로 페이지가 계속 사용자에게 표시됩니다. 서버에서는 클라이언트에서 게시한 보기 상태 데이터를 바탕으로 컨트롤 상태를 복원합니다. 렌더링 단계에 접어들면 ScriptManager 컨트롤은 UpdatePanel 영역을 새로 고쳐 브라우저로 돌려 보내기 위해 이 영역에 대한 렌더링을 격리시킵니다. 또한 페이지의 보기 상태 데이터가 수집되고 응답의 일부로 HTML이 전송됩니다. 그런 다음 브라우저의 스크립트에서 UpdatePanel의 이전 내용을 해당하는 새 HTML로 바꿉니다.

UpdatePanel 컨트롤에는 다음과 같이 Triggers와 ContentTemplate에 대한 요소가 포함될 수 있습니다.

<atlas:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
        ...
    </Triggers>
<ContentTemplate>
        ...
</ContentTemplate>
</atlas:UpdatePanel>

ContentTemplate 내의 영역은 ScriptManager 컨트롤이 비동기식으로 요청된 다시 게시 작업을 처리할 때 새로 고쳐집니다. Triggers 요소에는 ControlEventTrigger 및 ControlValueTrigger 요소가 포함될 수 있으며, 웹 페이지 개발자는 Triggers 요소를 사용하여 어떤 내용이 변경되었을 때 영역이 업데이트될 것인지 지정할 수 있습니다. 이렇게 하면 UpdatePanel 컨트롤에 직접 포함되지 않은 외부 컨트롤에 의해서도 변경이 이루어지도록 할 수 있습니다. 또한 간단한 선언을 사용하여 페이지의 동작과 UpdatePanel 컨트롤을 제어하고 가져온 새 데이터를 표시할 수 있습니다.

한 페이지에 여러 개의 UpdatePanel 컨트롤을 배치하고, 각 컨트롤을 업데이트하도록 하는 여러 Triggers를 추가할 수 있습니다. UpdatePanel 컨트롤의 내용은 특정 사용자 입력에 응답하는 데 필요한 최소한의 범위로 축소할 수 있습니다. UpdatePanel 컨트롤을 사용하면 기존의 ASP.NET 페이지를 크게 변경하지 않고도 사용자의 입력에 보다 빠르게 응답하도록 만들 수 있습니다.



페이지 맨 위로페이지 맨 위로


웹 서비스

웹 응용 프로그램은 서비스 지향 아키텍처를 중심으로 만들어집니다. 대화형 응용 프로그램을 가능하게 하는 핵심은 브라우저에서 서비스에 액세스할 수 있는 기능으로, Atlas에서 제공하는 서비스에는 두 가지 종류가 있습니다. ScriptManager 컨트롤은 다음과 같이 웹 서비스 참조를 위해 자동으로 생성되는 프록시를 사용합니다.

<atlas:ScriptManager EnablePartialRendering="true" runat="server">
    <Services>
        <atlas:ServiceReference GenerateProxy="true" 
         Path="~/nominees.aspx" Type="Custom"
    </Services>
</atlas:ScriptManager> 

이렇게 하면 클라이언트 쪽 구성 요소가 스크립트에서 웹 서비스를 직접 호출할 수 있습니다. 웹 서비스는 컨트롤에 바인딩되어 더욱 풍부한 동작을 지원합니다. 예를 들어 웹 서비스를 사용하여 관련된 정보를 검색하도록 xml-script에서 AutoCompleteBehavior를 정의할 수 있습니다(그림 9 참조).

동작은 페이지의 요소에 연결되어 해당 요소의 동작을 확장하며 .aspx 마크업에 설정되면 extender로 참조됩니다. AutoCompleteBehavior는 AutoCompleteExtender 컨트롤을 통해 요소와 연결될 수 있습니다. xml-script를 직접 작성하는 대신 extender가 서버의 컨트롤과 연결됩니다. 그런 다음 적절한 xml-script를 렌더링하여 클라이언트 쪽 동작을 가져옴으로써 컨트롤 동작이 확장됩니다. 웹 서비스를 호출할 때는 호출과 반환에 대한 결과가 대개 XML로 전달됩니다. 그러나 Atlas는 웹 서비스의 데이터를 JSON 형식으로 serialize할 수 있는 기능도 제공하므로 이를 통해 XML 사용으로 인한 일부 오버헤드를 줄일 수 있습니다. JSON 데이터는 브라우저에서 JavaScript 개체로 직접 deserialize될 수 있습니다. 이 밖에도 Atlas는 서버에서 사용되는 보다 복잡한 .NET의 관리되는 형식을 브라우저에서 JavaScript 개체로 serialize할 수 있는 기능을 지원하므로 브라우저에서 웹 서비스에 액세스하는 작업이 간단해집니다.

브라우저에서 사용할 수 있는 웹 서비스는 응용 프로그램의 일부인 사용자 지정 웹 서비스뿐만 아니라 ASP.NET 응용 프로그램 서비스까지 다양합니다. Atlas는 다음과 같이 JavaScript에서 폼 인증 서비스를 직접 사용할 수 있는 기능도 제공합니다.

Sys.Services.AuthenticationService.login(
    username, password, completionFunction);

사용자가 로그인 자격 증명을 제공할 때 HTML이 동적으로 변경될 수 있으므로 사용자는 로그인 페이지로 리디렉션된 후 원래 페이지로 되돌아가지 않아도 됩니다. .aspx 페이지에서 사용되는 프로필 데이터는 웹 서비스 호출을 통해서도 사용할 수 있으며 JavaScript 개체를 통해 서버에 저장된 프로필 데이터를 저장하거나 가져오는 기능도 제공됩니다.

응용 프로그램에서 사용하는 웹 서비스가 언제나 같은 호스트 서버에 있는 것은 아닙니다. 호스트 서버뿐 아니라 실제로 웹 서비스가 같은 도메인에 있어야 한다는 규칙도 없습니다. 그러나 브라우저는 페이지의 원래 출처가 아닌 도메인에 대해서는 XmlHttpRequest를 사용하는 호출을 차단합니다. 자식 요청을 시작하는 숨겨진 IFrame 개체를 사용하여 이 제한을 피하는 몇 가지 교묘한 방법이 있기는 하지만 실행하기가 상당히 번거롭습니다. Atlas에서는 웹 서비스 브리징을 제공하여 이 문제를 해결합니다. 웹 서비스 브리징을 사용하면 클라이언트가 다른 도메인으로 보내는 웹 서비스 호출을 시작할 수 있습니다. 이 호출은 Atlas 응용 프로그램으로 보내지며, 여기서 대상 서버로 요청을 프록시한 후 serialize하여 클라이언트로 결과를 돌려 보냅니다. 물론 Atlas는 IFrame 기술을 사용하여 다른 도메인과 직접 통신하는 기능도 제공합니다.



페이지 맨 위로페이지 맨 위로


결론

Atlas는 풍부한 기능을 갖춘 웹 응용 프로그램을 만들기 위한 다양한 기능을 제공합니다. 클라이언트 스크립트 라이브러리는 JavaScript를 작성하는 작업을 간소화하며 JavaScript를 작성할 때 개체 지향적 접근 방식을 사용하기 위한 구문을 제공합니다. 웹 서비스 기능을 사용하면 원격 및 로컬 서비스에 쉽게 액세스할 수 있습니다. 또한 복잡한 형식을 serialize하여 클라이언트와 서버에서 다양한 형식을 쉽게 이용할 수 있습니다. 서버 컨트롤 역시 클라이언트 스크립트 라이브러리를 이용하며 이를 통해 기존 응용 프로그램과 새 응용 프로그램에서 일반적으로 발생하는 '사용 대기를 위한 일시 중지'를 상당히 줄일 수 있습니다.

CTP 빌드는 업데이트, 변경, 새 기능 추가 등이 이루어져 거의 두 달에 한 번씩 새로 발표되고 있습니다. 궁극적으로 Atlas는 Visual Studio의 디자인 환경에서 사용할 수 있는 기능을 포함하여 다음 릴리스의 .NET Framework에 통합될 예정입니다. 근래에 Microsoft는 현재 사용 중인 사이트에 Atlas를 배포하여 웹 응용 프로그램에서 이용할 수 있는, 사용권이 제한된 버전의 Atlas를 발표했습니다. 자세한 내용을 보거나 최신 Atlas CTP를 다운로드하려면 atlas.asp.net (영문)을 참조하십시오.



페이지 맨 위로페이지 맨 위로

|

Taeyo's ASP.NET

   강좌 최초 작성일 : 2006년 02월 04일
   강좌 최종 수정일 : 2006년 02월 06일

   작성자 : Taeyo(김 태영)
   편집자 : Taeyo(김 태영)

   강좌 제목 : 웹에서의 비동기 호출 : Ajax와 Ajax.NET

강좌 전 태오의 잡담>

드디어 많은 분들이 기다리시던 Ajax(아작스)에 관계된 이야기입니다.
강좌를 쓰면서 이것 저것 살펴보다보니, 글 쓰는데만 일주일 이상이 걸렸네요.
하하하...


Ajax란?

아작스(Ajax:Asynchronous JavaScript And XML) 기술은 2005년 중반부터 화두로 떠오른 웹 기반의 비 동기 통신 기법을 의미하는 용어입니다. 이는 Google Earth가 발표되면서 사실상 급부상한 기술이기도 합니다. 웹 상에서 화면의 새로 고침(refresh)없이 그토록 빠르고, 깊이 있게 세계 지도를 확인할 수 있다는 것은 실로 놀라움이었으니까요. 해서, Ajax가 웹 상에서 고 해상도의 그래픽 지원을 가능하게 하는 기술이라고 착각하는 사람들도 있었고, 이 기술이 ActiveX를 대체할 수 있는 기술이라고 말씀하는 분들도 있었습니다. 아마도 각각의 기술이 사용되는 대상을 제대로 이해하지 못했기에 생긴 오해가 아니었나 싶습니다. 물론, 좁은 관점에서 보면 아주 틀린 말도 아닐 듯 합니다만.. 그래도… 좀 아닌 듯 한데… 음…

Ajax는 그 명칭이 의미하듯 단일 기술이라기 보다는 여러 기술을 하나로 묶은 것입니다. 예를 들면, Javascrpt, XML 등이 바로 그것에 해당합니다. Ajax는 SOAP 및 XML 같은 통신 기술을 사용하여 비 동기 요청/응답을 서버와 주고 받으며, JavaScript, DOM, HTML 및 CSS 같은 프레젠테이션 기술을 사용하여 응답을 처리하는 기술입니다. 다시 말해서, "서버로의 비 동기 통신 기술"과 "동적 클라이언트 스크립팅 기법"을 하나로 묶은 것이 Ajax라는 것입니다. 서버로의 비 동기 통신은 예전부터 지원되었던 속칭 XMLHTTP 컴포넌트(하단 박스 참조)를 이용하며, 클라이언트 스크립팅으로는 Javascript를 이용하기에, 대부분의 브라우저에서 Ajax를 이용할 수 있습니다.

저는 비 동기 호출을 위해 사용되는 브라우저 지원 개체를 'XMLHTTP 컴포넌트'라고 표현했습니다만, 이는 공식명칭은 아닙니다. 그냥 제가 그렇게 부르는 것이니 양해하십시오. 실제적인 이 컴포넌트의 모습은 브라우저 별로 약간의 차이가 있습니다. 간단히 설명하자면, Firefox, 모질라, Opera류의 경우는 비 동기 호출을 위해서 window.XMLHttpRequest를 이용합니다. 하지만, IE(6.0 이하 버전)의 경우는 안타깝게도 그를 사용하지 못하며 ActiveXObject인 Microsoft.XMLHTTP를 사용해야만 합니다. 좀 아쉽죠. 하지만, IE 7부터는 window.XMLHttpRequest를 지원한다는 기쁜(?) 소식이 있으니 약간은 위안이 됩니다(정말? 이게 위안이 될까?).

좀 더 쉽게 설명하자면, Ajax를 사용하면 브라우저를 새로 고칠 필요 없이, JavaScript를 이용하여 서버 측의 메서드를 실행하고, 그 결과 데이터를 받아볼 수 있다는 것 입니다. 즉, 사용자 모르게 백그라운드에서 서버와의 요청/응답을 처리할 수 있다는 것이죠.

Ajax의 역사?

Ajax가 상당히 새로운 기술 같지만 사실상 이 기법은 기존 ASP 시절부터 중급 웹 프로그래머들이 자주 써왔던 비 동기 통신 기법이 신기술과 맞물려 정리된 기술이라 볼 수 있습니다. 예전에도 이와 유사한 기술은 존재했습니다. 예를 들면, 고전적으로 사용되었던 방법 중 하나로는 IFRAME을 통한 비 동기 통신 기법이 있었습니다. 화면 새로 고침 없이 IFRAME을 이용하여(일종의 별도의 채널) 데이터를 가져와 DHTML을 통해서 동적으로 기존 화면에 데이터를 반영하는 방법이 바로 그것이죠. 이 방법도 어떻게 보면 현재의 Ajax와 개념 자체는 유사한 기법이라 할 수 있겠습니다. 현재의 기법에 비하면 대단히 조악하긴 하지만 말입니다. 사실, 실제적인 Ajax의 모체가 된 기술은 XMLHTTP 컴포넌트를 이용한 비 동기 통신 기법이었습니다. 이는 현재의 Ajax에서도 그대로 사용되고 있기도 합니다(내부적으로 말이죠). XMLHTTP 컴포넌트를 이용하게 되면 기존 땜빵 식의 IFRAME 방식에서 벗어나 보다 직관적인 비 동기 통신 기법을 구현할 수 있습니다.

하지만, XMLHTTP 적용 초기에도 데이터 포맷 때문에 약간의 피곤함은 있었습니다. 즉, 서버 측과의 비 동기 통신 채널을 위해 XMLHTTP를 이용할 수 있긴 했지만, 통신으로 주고받는 데이터에 대한 표준은 정해지지 않았기 때문입니다. 해서, 그 당시에는 주로 구분자를 끼워서 구성한 문자열을 주고 받곤 했었습니다. 예를 들면, 서버에서는 데이터를 "김태영\김덕영\김영현"와 같은 형태로 반환하고, javascript는 이 데이터를 받아서 "\"로 분리하여, 각각의 값을 뽑아내 사용하는 일을 반복해야 했었던 것이죠. 이러한 노가다 성 작업은 언젠가는 해결되어야 할 숙제가 아닐 수 없었습니다.

하지만, XML 등장과 함께 그 숙제도 자연스럽게 해결이 되었습니다. 해서, 기존 비 동기 통신 기법에 XML이 멋들어지게 결합되면서 현재의 Ajax가 나타나게 된 것입니다. XML이 업계 표준이 되기 이전, 자기들만의 데이터 포맷을 사용했었기에 수반될 수 밖에 없었던 개발상의 난독성 및 복잡성이 XML을 반영함으로써 개선되고 정리된 것이죠.

해서, 명칭이 바로 Asynchronous JavaScript And XML인 것입니다. ^^

참. 오해하실까 봐 말씀을 드리자면, Ajax는 MS의 기술도 그 누구의 기술도 아닙니다. 이는 추상적인 기술에 대한 용어일 뿐입니다. 인터넷이라는 단어가 그 어떤 제품의 단어가 아니듯이 말이죠(비유가 이상한가요? ^^). MS 진영에서는 이러한 Ajax를 더욱 개발자가 이용하기 편하도록 프레임워크와 API를 현재 개발하고 있는데요. 아마도 2006년 중반기에는 그 모습이 드러나지 않을까 싶습니다. 코드명은 Atlas이고, 현재는 알파 버전(가장 최신은 2005년 12월 버전)만이 공개되어 있습니다. ^^

핫? 그렇다면, 기왕이면 아틀라스(Atlas)에 대한 이야기로 이번 강좌가 진행되면 좋을 것 같다구요? 음.. 그렇다면, 죄송합니다. 안타깝게도 아틀라스를 이번 강좌에서 다루기는 어려울 듯 합니다. 물론, 3월에 있을 INETA 컨퍼런스에서는 Ajax와 Atlas에 대한 내용을 발표할 예정에 있긴 합니다만, 아직은 알파 버전이고 해서 강의라면 모를까 강좌로는 그 내용을 풀어쓰기가 쉽지 않을 듯 하네요(왜? 왜? 무슨 차이가 있는데?? -_-)

Ajax.NET

그렇다면, 이번 강좌에서는 Ajax에 대한 무슨 이야기를 하려 하느냐? 그것이 궁금하시죠? 사실 Ajax에 대한 데모를 보고 싶다 하시면, 이미 지 지난 번에 연재한 비 동기 호출 강좌의 2번째 강좌인 "XMLHTTP" 강좌를 통해서 이미 한번 경험한 것이나 다를 바 없습니다. 그 또한 XML 데이터를 이용하지 않았다 뿐이지 일종의 Ajax 기법이라 할 수 있기 때문이죠. 그것으로 부족하시다면, 지난 강좌이자 세 번째 강좌였던 WebService Behavior를 떠올리셔도 됩니다. 그 강좌는 실로 완전한 Ajax 예제라 할 수 있을 것입니다. 고로, 여러분은 이미 알게 모르게 Ajax를 접했던 것입니다(단, 기존 강좌를 읽은 분만 여기에 해당됨).

하지만, 여러분이 원하는 Ajax 예제는 그것이 아니라는 것을 압니다. 보다 쉽게, 더 간편하게 Ajax를 이용할 수 있는 방법을 원하시는 것이죠? 물론입니다. 해서, 이번 강좌에서 진행하려는 것은 지난 9월에 MSDN에 올라온 컬럼(ASP.NET Spiced: Ajax)을 기반으로 해서 Ajax.NET에 대해 알아보는 내용으로 진행해볼까 합니다. 링크는 http://www.microsoft.com/korea/msdn/asp.net/default.aspx?pull=/korea/msdn/library/ko-kr/dnaspp/html/ASPNetSpicedAjax.asp 이구요.

그 컬럼에서는 Ajax의 소개와 함께 Ajax.NET이라는 것을 소개하고 있는데요. 이는 ASP.NET 분야의 MVP인 Michael Schwarz라는 사람이 개발한 .NET을 위한 Ajax용 라이브러리입니다. 주의하실 점은 그 제품이 MS가 제공하는 라이브러리는 아니라는 점입니다. ^^ 하지만, 상당히 쓸만한 라이브러리이기에 MS 컬럼에도 소개되었죠. 그 컨셉이나 사용방법이 상당히 편리하고 기발해서 주목을 받기도 했습니다. 게다가, 그 라이브러리는 WebService Behavior이 제공하지 않았던 데이터 타입인 DataSet이나 DataTable도 지원하더군요. 개발자의 블로그는 http://weblogs.asp.net/mschwarz/ 입니다. 관심있는 분은 한번쯤 가 봐도 좋을 듯 합니다.

용어가 혼란스러울까봐 잠시 정리하고 넘어가면, Ajax는 클라이언트에서 서버 측 함수를 비 동기적으로 호출하기 위한 프레임워크를 말하는 것이고요. 특정 회사의 제품명이 아닙니다(앞에서 누누히 강조 드렸습니다).

반면, Ajax.NET은 Ajax 프레임워크를 활용하는 솔루션을 구축하는 데 도움이 되는 특정 구현을 말합니다. 즉, Ajax 구현을 위한 개발 도구 중 하나가 Ajax.NET 이라는 것입니다. 물론, 2006년 중반에는 Ajax 구현을 위한 MS의 개발 프레임워크도 발표되겠지만 말입니다(오픈소스 진영에서는 AjaxTags라는 라이브러리가 개발 및 릴리즈되고 있는 것으로 압니다).

약간 김이 새신다구요? 왜 우리가 MS가 제공하는 것도 아닌 다른 개발자(물론 고수겠지만)의 제품을 이용해서 Ajax를 개발해야 하냐구요? 물론, 그렇게 우울해할 수도 있긴 할 것입니다. 하지만, 솔직히 강좌를 읽고 계시는 분들 중 많은 분들이 몇 시간 또는 몇 일에 걸쳐 Ajax의 본질을 이해하려 하기 보다는, 당장 Ajax를 사용하는 응용 프로그램을 만들어서 "아~ 아작스가 이런 것이구나. 뭐 별거 아니네" 혹은 "오.. 아작스. 완전 아작인데!!!" 하고 싶을 것입니다. 해서, 그러한 욕구를 충족시키기 위해서 이번 강좌를 진행하려 하는 것입니다. ^^ (막상 해 보시면 재미있어 하실걸요~)

다음은 참고 삼아, 제 맘대로 정리해 본 MS의 Ajax History입니다. ^^; 제 맘대로 정리한 것이기에 자료의 신빙성을 100% 보장할 수는 없습니다. 하하하

자. 그럼 이제 본격적인 시작을 한번 해 보겠습니다.

Ajax.NET 예제

우선, 위의 MS 컬럼에서 Ajax.NET 데모소스를 다운로드 받도록 하세요. '링크 찾아가기 귀찮아요. 바로 다운로드 하게 해 주세요' 하시는 분들을 위해 여기에도 링크를 걸도록 하겠습니다.

다운로드 : (C# 버전) AjaxASPNETCS.msi
다운로드 : (VB.NET 버전) AjaxASPNETVB.msi

받아서, 설치를 하시고 나면 Ajax with ASP.NET (C#)이라는 폴더가 생길 것입니다. 저의 경우는 설치를 [내 문서] 쪽에 했기에 다음 경로에 생겼습니다. 일단, 설치하셨으면 해당 폴더를 AjaxSampleCS라는 이름의 가상 디렉터리로 잡아주셔야 합니다(왜 설치 시에 그 작업까지 자동으로 되지 않는지 약간 서운하기도 합니다만).

다 되셨으면, VS.NET 2003을 실행하시고, 해당 폴더에서 AjaxSampleCS.sln 파일을 실행합니다. 그러면, 웹 프로젝트가 로드 될 것입니다.

이 예제를 실행하기 위해서는 반드시 VS.NET 2003이 필요합니다.

대략 4개의 샘플이 존재하는 데, 저는 이 중 첫 번째 샘플인 DropDownLink 만을 같이 살펴보도록 하겠습니다. 한 가지만 다루어보면 다른 것들은 여러분이 스스로 파악이 가능하실 듯 하니까요 ^^

우선, 같이 살펴볼 페이지의 실행 결과부터 보도록 하겠습니다. 프로젝트를 빌드 하신 뒤에 Sample1 폴더에 존재하는 DropDownLink.aspx 페이지를 [브라우저에서 보기] 하세요. 그럼 다음과 같이 심플한 데모 페이지가 브라우저에 그 모습을 드러낼 것입니다.

데모는 매우 심플합니다. 첫 번째 드롭다운에서 국가를 선택하면, 우측 드롭다운에 해당 국가의 주(State)들이 나열되는 형태입니다. 물론, 페이지의 포스트백이 전혀 없이 말입니다.

얼핏 보기에도 훌륭하지 않나요?

하는 김에, 두 번째 데모도 실행해 볼까요? 두 번째 데모는 많은 분들이 요긴해 하실 만한 자동완성 기능의 구현입니다. Sample1 폴더의 SearchCompletion.aspx 페이지를 실행해 보세요. 단순해 보입니다만, 이 데모도 상당히 재미있습니다. 텍스트 박스에 'a' 이라고 입력하면 그 즉시 'a'로 시작하는 모든 도시명이 리스트박스에 출력되고, 'al'이라고 입력하면 그 즉시, al로 시작하는 모든 도시명이 하단에 출력되는 자동완성 기능입니다.

두 예제는 실행 모습이 서로 다르지만 내부적으로는 상당히 유사하기에, 강좌에서는 이 중 첫 번째 예제만을 같이 한번 살펴보려 합니다. 그러면, 두 번째 예제는 혼자서도 잘해요~ 할 수 있을 것이라 믿어 의심할 꺼~~야!!

일단, [솔루션 탐색기]에서 [참조] 폴더를 보시면 Ajax라는 것이 존재하는 것을 볼 수 있습니다. 물리적인 폴더의 bin 디렉터리에는 이에 해당하는 Ajax.dll이 존재하고 있고요. 이것이 Ajax.NET의 핵심모듈입니다. Ajax.NET을 이용하고 싶다면, 단지 이 DLL만을 참조해 쓰면 되는 것이죠.

또한, Sample2에는 DAL.cs 파일이 존재하는 것을 볼 수 있는데요. 이 부분은 국가명을 가져오거나(GetShippingCountries), 특정 국가의 주 명칭을 얻어오는 함수(GetCountryStates) 등이 들어있습니다. 일종의 데이터 액세스 클래스라고 보시면 될 듯 합니다. 첫 번째 예제는 이 DAL.cs의 함수들 중에 국가 명을 얻어오는 GetShippingCountries() 메서드와 지정된 국가의 주 명칭을 얻어오는 GetCountryStates() 메서드를 사용하게 됩니다. 각각은 DataTable과 DataView를 반환하도록 작성되어 있고요.

물론, 반드시 이렇게 데이터 액세스 컴포넌트를 만들어 써야 하는 것은 아니지만, 메서드의 재 사용성을 위해서라도 이렇게 구성해 쓰는 것이 바람직하다 할 수 있겠습니다. 여기서 N-Tier(Layer) 이야기를 꺼내는 것은 약간 주제에 어긋나는 것이기에 그 쪽 관련 설명은 여기까지만 하기로 하겠습니다. 실제적으로 우리가 관심있는 부분은 Ajax이니까요.

자 그럼 이제 본격적으로 DropDownLink.aspx 페이지의 코드 비하인드 소스를 살펴보도록 하겠습니다. 그 소스는 다음과 같습니다(일단은 버튼 submit 부분은 빼고 살펴보도록 하겠습니다)

namespace AjaxSampleCS.Sample1
{
    public class DropDownLink : Page
    {
        protected DropDownList countries;
        protected DropDownList states;
        protected Button submit;

        private void Page_Load(object sender, EventArgs e)
        {
            // 이 클래스의 메서드를 클라이언트 측에서 호출이 가능하게 하기 위해서 AjaxMethod로 표시
            Ajax.Utility.RegisterTypeForAjax(typeof(DropDownLink));
            if (!Page.IsPostBack)
            {
                countries.DataSource = DAL.GetShippingCountries();
                countries.DataTextField = "Country";
                countries.DataValueField = "Id";
                countries.DataBind();

                countries.Items.Insert(0, new ListItem("Please Select", "0"));
            }
        }

        [Ajax.AjaxMethod()]
        public DataView GetStates(int countryId)
        {
            return DAL.GetCountryStates(countryId);
        }

        …

원래 소스에서 주석은 영어로 표기되어 있으나, 여기서는 제가 번역해서 표현해 보았습니다. 착하죠? -_-a

일단, ASPX 페이지에서 준비가 되어야 할 것들은 무엇일까요?

1) 폼이 처음 로드 될 경우, 첫 번째 드롭 다운 컨트롤에 국가 명을 로드 하는 작업을 수행해야 합니다. 물론, 이는 Ajax와는 무관한 작업이죠. 그래서, 보시다시피, Page_Load에는 그러한 코드가 들어있는 것을 확인할 수 있습니다.

2) 첫 번째 드롭 다운 컨트롤에서 선택이 일어날 경우, Ajax를 통해서 두 번째 컨트롤에 해당 국가의 주(State)명을 로드해야 합니다. 이 부분이 우리의 핵심이죠. 그리고, 이 결과를 얻기 위해서 Ajax에서는 2가지의 작업으로 분리가 됩니다.

1. 지정된 국가의 주명을 얻어오는 서버 측 함수(Javascript에서 호출이 가능한) 제작
2. 그러한 서버 측 함수를 호출하고 얻어온 결과 데이터를 폼에 반영하는 자바스크립트 제작

이 중 서버 페이지인 ASPX 측에서는 1번이 준비되어야 할 것입니다. 해서, 소스를 보시면 바로 그러한 역할을 수행하는 GetStates(int countryId) 메서드가 있는 것을 볼 수 있습니다. 단, 이 메서드는 일반 메서드가 아닌 'Javascript에서 호출이 가능한 서버 함수'여야 합니다. 그래야 Ajax가 올바르게 구현되는 것이니까요.

맨땅에서 'Javascript에서 호출이 가능한 서버 함수'를 구현하는 것은 그리 쉬운 일이 아닙니다. 그렇기에, 여기서 Ajax.NET이 필요한 것입니다. Ajax.NET을 이용하게 되면 단지 'Javascript에서 호출이 가능한 서버 함수'를 만들기 위해서 해 주어야 할 것은 해당 함수 명 위에 간단한 Ajax.NET 어트리뷰트를 하나 추가하기만 하면 됩니다.

[Ajax.AjaxMethod()]

라는 어트리뷰트를 말이죠. 정말로 간단하죠? 단지 이것을 지정하는 것만으로 해당 함수는 'Javascript에서 호출이 가능한 서버 함수'가 되는 것입니다. ^^

단, Ajax.NET을 올바르게 구동시키기 위한 [필요조건]이 하나 존재하고 있는데요. 그것은 추가적으로 서버 함수가 들어있는 클래스가 무엇인지를 Ajax.NET에게 알리는 것입니다. 해서, Page_Load 이벤트 안에는 다음과 같은 코드가 반드시 추가되어야 합니다.

Ajax.Utility.RegisterTypeForAjax(typeof(DropDownLink));

이는 필수적으로 넣어주어야 하는 것입니다. Ajax.NET을 사용한다면 말이죠.

현재의 예제는 'Javascript에서 호출이 가능한 서버 함수'를 ASPX 페이지 클래스 안에 같이 두고 있지만, 개발자에 따라서는 이를 별도의 클래스로 분리하고 싶을 수도 있을 것입니다. 예를 들면, 다음과 같이 말이죠.

namespace AjaxSampleCS.Sample1
{
    public class MyAjaxClass
    {
        [Ajax.AjaxMethod()]
        public DataView GetStates(int countryId)
        {
            return DAL.GetCountryStates(countryId);
        }
    }

    public class DropDownLink : Page
    {
        protected DropDownList countries;
        protected DropDownList states;
        protected Button submit;

        private void Page_Load(object sender, EventArgs e)
        {
            Ajax.Utility.RegisterTypeForAjax(typeof(MyAjaxClass));
            if (!Page.IsPostBack)
            {
                countries.DataSource = DAL.GetShippingCountries();
                countries.DataTextField = "Country";
                countries.DataValueField = "Id";
                countries.DataBind();

                countries.Items.Insert(0, new ListItem("Please Select", "0"));
            }
        }

        …

이런 경우에는 Page_Load 이벤트에서 Ajax용 클래스 등록이 다음과 같이 변경되어야 합니다.

Ajax.Utility.RegisterTypeForAjax(typeof(MyAjaxClass));

즉, 실제 Ajax용 함수가 존재하는 클래스를 등록해 주어야 한다는 것입니다. 어렵지 않죠? 이것으로 서버 측의 설정은 끝입니다. 너무나도 간단합니다. 단지, 필요한 함수를 만들고, Ajax용 어트리뷰트만 지정해 주면 되는 것입니다. 물론, Page_Load 이벤트에 Ajax용 클래스를 등록해주는 것도 잊어서는 안되겠죠?

자. 그렇다면 이제는 클라이언트 측의 Javascript를 한번 살펴볼까요? DropDownLink.aspx 파일의 HTML 부분을 살펴보면 다음과 같습니다.


    …

    <form id="form" method="post" runat="server">
        <Common:Header runat="server" ID="Header1"/>
        <div class="content">
            <h4>Please select a Province or State to ship to</h4>
            <asp:DropDownList onChange="LoadStates(this)" ID="countries" Runat="server" />
            <asp:DropDownList ID="states" Runat="server" />
            <asp:Button ID="submit" Runat="server" Text="Submit" />
        </div>
    </form>
  </body>
</HTML>

<script language="javascript">
//states 드롭다운
var statesList = document.getElementById("<%=states.ClientID%>");

// 드롭다운에서 onChange 이벤트가 일어날 경우 호출된다
function LoadStates(countries)
{
    var countryId = countries.options[countries.selectedIndex].value;
    if (countryId > 0)
    {
        //DropDownLink는 우리가 등록해 놓은 타입 명이기에, Ajax.NET에 정의되어 있다
        DropDownLink.GetStates(countryId, LoadStates_CallBack);
    }
    else
    {
        // states 드롭다운을 깨끗이 비운다.
        states.options.length = 0;
    }
}
// Ajax.NET이 응답 데이터를 전달하는 콜백 함수
function LoadStates_CallBack(response)
{
    // 만일, 서버 코드가 예외를 일으킨다면
    if (response.error != null)
    {
        alert(response.error); //아마도 이보다는 더 나은 처리가 필요할 것이다.
        return;
    }

    var states = response.value;
    // 기대했던 응답 데이터가 아니라면
    if (states == null || typeof(states) != "object")
    {
        return;
    }

    statesList.options.length = 0; //reset the states dropdown
    // JavaScript는 대,소문자를 구분하기에 Length의 L은 반드시 소문자로 해야 한다.
    // (아마도 개발자가 그렇게 정의해 놓은 듯하다)
    for (var i = 0; i < states.Rows.length; ++i)
    {
        statesList.options[statesList.options.length] = new Option(states.Rows[i].State, states.Rows[i].Id);
    }
}
</script>

HTML 쪽에서 관심을 가질 부분은 첫 번째 드롭다운 컨트롤의 onChange 이벤트입니다. 이는 다음과 같이 작성되어 있습니다. onChange="LoadStates(this)". 여기서, 우리는 LoadStates 함수가 바로 서버 함수를 비 동기적으로 호출하는 핵심일 것임을 눈치채실 수 있습니다.

이제 JavaScript 쪽을 한번 살펴보도록 하겠습니다.

일단, 스크립트가 시작하는 부분에서는 첫 번째 드롭다운 컨트롤 개체를 statesList라는 변수에 할당하고 있습니다. 드롭다운 개체를 얻기 위해서는 document.getElementById() 메서드를 이용하는데요. 이는 특정 이름를 갖는 폼 개체를 반환하는 메서드입니다. 주의할 부분은 드롭다운 컨트롤의 이름으로 'states'가 아닌 "<%=states.ClientID%>"를 사용한다는 점입니다.

이렇게 지정하는 이유는 드롭다운 컨트롤이 서버 컨트롤이기 때문입니다. 서버 컨트롤은 서버에서의 컨트롤 ID는 states이지만, 브라우저의 출력 HTML 에서는 그 ID가 동적으로 재 생성될 수도 있습니다. 특히, 컨트롤이 Panel과 같은 컨테이너 안에 들이었을 경우에는 말입니다. 예를 들면, 그러한 경우 ctl0_states와 같이 바뀌어 생성될 수 있다는 것입니다. 해서, 서버 컨트롤이 HTML로 렌더될 때 실제로 할당될 이름을 알려주는 "<%=states.ClientID%>"를 사용한 것입니다. (물론, 현재의 경우는 그 이름 그대로 만들어질 것이긴 합니다만... ^^)

그리고, 이어서 LoadStates(countries) 함수가 존재합니다. 이 함수는 사용자가 첫 번째 드롭다운에서 국가를 선택할 경우 호출됩니다. 그리고, 바로 이 함수가 비 동기 호출을 수행하는 핵심 함수이기도 하죠. 그러면, 그 때 어떠한 일이 일어나는지 이제 LoadStates 함수의 내부를 한번 살펴보도록 하겠습니다.

우선은 첫 번째 드롭다운 컨트롤(countries)에서 현재 선택된 국가 값을 얻어와서 countryId라는 지역 변수에 담습니다. 그리고, 그 선택된 값이 0보다 크다면 즉, 어떤 국가가 선택된 상태라면 비 동기 호출을 수행하고, 선택된 값이 0이라면 두 번째 드롭다운 컨트롤을 초기화하는 작업을 수행합니다.

function LoadStates(countries)
{
    var countryId = countries.options[countries.selectedIndex].value;
    if (countryId > 0)
    {
        //DropDownLink는 우리가 등록해 놓은 타입 명이기에, Ajax.NET에 정의되어 있다
        DropDownLink.GetStates(countryId, LoadStates_CallBack);
    }
    else
    {
        // states 드롭다운을 깨끗이 비운다.
        states.options.length = 0;
    }
}

핵심은 DropDownLink.GetStates(countryId, LoadStates_CallBack); 입니다. 이 부분이 재미있는 부분입니다. 서버에 존재하는 특정 서버함수로의 비 동기 호출을 하기 위해서 어떤 식으로 접근해야 하는지를 보여주는 코드이죠. 보시다시피, DropDownLink.GetStates 라는 코드로 서버 함수를 접근하고 있습니다. 규칙은 다음과 같습니다.

[비 동기 호출용 Ajax 클래스명].[호출할 Ajax 메서드] (필요한 인자, 콜백 함수명)

앞의 aspx 코드에서 우리는 Page_Load 시에 Ajax용 클래스를 DropDownLink로 등록했고, 또한 Ajax 호출용 메서드로 GetStates를 만들어 두었기에, 호출하는 문법은

DropDownLink.GetStates(countryId, LoadStates_CallBack);

와 같이 구성되는 것입니다. 재미있는 것은 메서드의 두 번째 인자인 LoadStates_CallBack 입니다. 이는 비 동기 호출을 수행하고 그 결과를 받게 되는 Javascript의 콜백 함수를 지정하는 부분입니다. 다시 말해서, 서버로의 비 동기 호출을 수행한 뒤, 결과 데이터를 LoadStates_CallBack라는 Javascript 함수에게 넘겨주겠다는 의미가 되는 것이죠.

고로, LoadStates_CallBack라는 이름의 Javascript 함수도 존재해야 합니다. 그리고, 이 콜백 함수의 역할은 서버에서 넘겨준 결과 데이터를 가지고 웹 페이지에 동적으로 반영하는 역할을 수행해야 할 것입니다.

해서, 이어지는 코드가 바로 그것입니다.

// Ajax.NET이 응답 데이터를 전달하는 콜백 함수
function LoadStates_CallBack(response)
{
    // 만일, 서버 코드가 예외를 일으킨다면
    if (response.error != null)
    {
        alert(response.error); //아마도 이보다는 더 나은 처리가 필요할 것이다.
        return;
    }

    var states = response.value;
    // 기대했던 응답 데이터가 아니라면
    if (states == null || typeof(states) != "object")
    {
        return;
    }

    statesList.options.length = 0; //reset the states dropdown
    // JavaScript는 대,소문자를 구분하기에 Length의 L은 반드시 소문자로 해야 한다.
    // (아마도 개발자가 그렇게 정의해 놓은 듯하다)
    for (var i = 0; i < states.Rows.length; ++i)
    {
        statesList.options[statesList.options.length] = new Option(states.Rows[i].State, states.Rows[i].Id);
    }
}
</script>

서버에서 처리된 결과는 함수의 인자인 response로 넘어오게 됩니다. 이 방식은 Webservice Behavior를 사용할 경우(세 번째 강좌)와 동일합니다. ^^

코드를 주~욱 설명하자면 다음과 같습니다.

1. 에러가 발생했다면, 에러 메시지를 메시지박스로 나타내고 작업을 포기한다.
2. 응답 데이터를 states 변수에 담은 다음, 그 값이 null 이거나, 그 형식이 object가 아니라면
    작업을 역시 포기한다.
3. 두 번째 드롭다운 컨트롤을 초기화 하고, states의 행 만큼 반복하면서 데이터를 꺼내
    드롭다운 컨트롤에 추가한다.

재미있는 부분은 서버에서 반환된 DataView 데이터를 마치 실제 DataView를 쓰는 것처럼 states.Rows[i].State, states.Rows[i].Id와 같은 식으로 접근할 수 있다는 것입니다. 이는 Ajax.NET을 제작한 Schwarz가 추가적으로 스크립트 작업을 해 두었기에 가능한 것입니다.

어떻습니까? 크게 어렵지는 않죠?

사실, 많은 작업이 Webservice Behavior 강좌에서 다루었던 부분과 유사합니다. 아마도 그렇게 느끼신 분이 많을 것입니다. 다만, 직접 XMLHTTP를 다루었을 때에 비해 편해진 점이라면,

1. 서버 메서드를 굳이 웹 서비스 메서드로 만들지 않아도 된다는 점
2. 그럼으로 해서, 서버 쪽 모듈 구성이 상대적으로 편해졌다는 점
3. 호출할 서버 페이지의 경로를 지정하지 않아도 된다는 점
4. Javascript에서 비 동기 호출을 위해 필요한 코드가 간소해졌다는 점

등을 들 수 있을 것입니다.

그리고, 이러한 장점 중 좋은 점들은 ASP.NET 2.0 Atlas에도 반영이 되고 있습니다. Atlas의 알파버전을 살펴보면, 서버 모듈을 웹 서비스로 제작해야 한다는 부분만 제외하면 다른 장점들은 좋은 점만 쏙쏙 뽑아서 고스란히 녹아있습니다. ^^

서버 모듈을 웹 서비스로 분리하는 부분은 서버 모듈의 재 사용성 및 외부 인터페이스와의 통합을 위해서도 탁월한 선택이라 생각합니다. Atlas의 실제 모습은 뚜껑을 열어봐야 알 수 있는 부분이긴 하지만, 그래서 살포시 기대가 되는 것은 사실입니다.

어떤가요? 크게 어렵지가 않죠? 맨땅에서 구현하는 것보다 Ajax.NET과 같은 도구를 사용하는 것이 훨씬 개발하기가 수월하다는 것을 느끼실 겁니다. ^^

그런데, 이게 끝이 아닙니다. Ajax.NET을 이용하는 경우에는 현재 한 가지의 단점을 가지고 있습니다. 물론, 이를 Ajax.NET의 문제라고 단정적으로 이야기하기는 좀 그렇습니다만 말입니다. 그것은 바로 동적으로 데이터를 채운 컨트롤의 VIEWSTATE는 유지되지 않는다는 것입니다(어찌보면 당연한 이야기겠지만 말입니다)

이해가 되지 않는다구요? 그렇다면, 다음과 같은 상황을 생각해 보시면 쉽니다.

DropDownLink 데모에서, 국가를 선택하면 두 번째 드롭다운에 주(State) 명이 주욱 나타나죠? 물론, 그 데이터는 자바스크립트를 통해서 동적으로 넣은 데이터일 것입니다. 그 상태에서 서브밋 버튼을 클릭하면 어떻게 될까요?

페이지는 포스트백이 될 것이고, 현재 선택된 국가명과 주명이 화면에 찍혀 나오거나 할 것입니다. 그런데, 포스트백된 화면에서는 주명을 나열하는 두 번째 드롭다운 컨트롤의 데이터는 모두 사라질 것입니다. 그 데이터는 Javascript를 통해서 동적으로 넣은 값인지라 서버에서는 그 값에 대해서 전혀 모르기 때문입니다.

해서, 대안으로 DropDownLink.aspx 데모에서는 버튼 클릭 이벤트(코드 비하인드 파일)에서 다음과 같은 처리를 추가적으로 하고 있는 것을 볼 수 있습니다.

    private void submit_Click(object sender, EventArgs e)
    {
        //states 드롭다운은 클라이언트 측에서 값을 채웠다는 것을 기억하라.
        //이는 그 값들이 viewstate에 유지되지 않는다는 것을 의미한다.
        //그렇기에, 드롭다운에서 선택된 값을 얻어오는 유일한 방법은 Request.Form을 이용하는 것이다.
        string selectedStateId = Request.Form[states.UniqueID];
        Response.Write("You selected province/state id: " + selectedStateId);

        //이는, 사용자가 선택한 값을 폼에 나타내려 할 경우 추가 작업이 필요하다는 것을 의미한다.
        states.DataSource = DAL.GetCountryStates(Convert.ToInt32(countries.SelectedIndex));
        states.DataTextField = "State";
        states.DataValueField = "Id";
        states.DataBind();
        states.SelectedIndex = states.Items.IndexOf(states.Items.FindByValue(selectedStateId));     }

이 작업은 주석에서 대략적으로 설명하고 있듯이 사용자가 선택한 국가명을 가지고, 서버에서 그 국가에 해당하는 주(state)명을 얻어와 두 번째 드롭다운에 채운 다음, 사용자가 선택한 값을 드롭다운 컨트롤에서 선택된 것으로 표현하는 것입니다.

이는 뭔가 반복적인 작업이 아니냐는 볼멘 소리가 나올 수도 있겠지만, 어쩔 수 없이 처리해 줘야 하는 부분입니다. 사실, 이 부분도 그나마 ASP.NET을 이용하니까 이 정도의 처리로 가능한 부분입니다. ASP 시절에 이와 같은 처리를 하려면 수많은 Javascript 코드를 이용해서 클라이언트 측에서 데이터를 다시 채우는 작업을 반복해야 할테니까요.

어쨌든 이로써 예제는 마무리 되어 있습니다.

프로그래밍 방식을 모두 다 확인한 지금의 여러분이라면, 'Ajax 프로그래밍이 그다지 쉽지 않네~ 얘 뭐야..' 할 지도 모르겠습니다만, 이는 맨땅부터 작업하는 방식에 비하면 상당히 개발이 쉬어진 형태입니다. Ajax 스타일의 프로그래밍을 이미 접해본 개발자라면 제 의견에 동감하실 것입니다.

Ajax가 앞으로의 세상을 바꿀 것이고, 편리하게 만들 것이라는 분위기가 조성되어 가고 있지만 이는 사실 사용자 측면에 해당하는 것이지 개발자 측면이라고 보기는 조금 애매합니다. 사실, Ajax를 도입하면 사용자의 사용성은 좋아질지 모르겠지만, 이를 개발하고 적용하는 개발자 측면에서는 손이 더 많이 가게 되는 것이 사실이기 때문입니다. 해서, 그러한 개발 생산성을 더욱 높이고자 MS를 비롯한 업체들이 Ajax용 프레임워크를 개발하고 있는 것이죠. 말씀드렸다시피, Atlas가 바로 그런 목적으로 준비되고 있고요.

Atlas가 나올 경우, 얼마나 개발 생산성이 높아질 것인가는 뚜껑을 열어봐야 알 수 있는 부분이라 제가 말씀드리기 조심스럽지만, 알파버전을 살포시 맛 본 입장에서 말씀드리자면, 적어도 Ajax.NET을 이용하는 것보다는 상당히 나을 듯 하다는 느낌입니다.

중요한 것은 Ajax용 프레임워크가 제공되던, 제공되지 않던 개발자는 가능하다면 Ajax의 내부적인 흐름과 프로세스를 이해하고 있을 필요가 있다는 점입니다. 그렇다면, 간혹 주어지는 난제를 풀어 낼 실마리를 스스로 찾아낼 수 있을테니까요. 단순히, 갖춰진 틀 안에서만 프로그래밍이 가능하다면 고객의 특별한 요구사항이 있을 경우 막다른 길에 막힌 듯한 상황을 접하게 될 가능성이 큽니다. 즉, '이건 원래 안 되요(속으로는 가능한 방법이 있을 것 같긴 한데.. 하면서)' 와 같은 말로 둘러대야만 하는.. 슬픈 상황을 경험하게 될 것이라는 이야깁니다. 안 된다고 이야기할 때는 꺼림직한 구석 없이 단호하게!! '이건 안됩니다' 라고 시원하게 이야기할 수 있는 개발자이고 싶다면.. 백그라운드도 조금은 살펴봐 두시는 것이 좋습니다(적어도 이전 제 강좌를 살펴보신다면 그것으로도 어느 정도는 충분하지 않나 하는.. -_-;; 부족한가여? 그럼 어쩌지???).

사실, 저도 이런 말 할 자격은 없는 사람입니다만… 말입니다. 그래서, 더욱 노력하는 삶을 살아야 하지 않나 생각하며 반성합니다.

히힛. 이번 강좌는 좀 많이 길었는데요. ^^ 그래서, 강좌가 올라온 것도 좀 많이 늦어졌죠? 담에는 조금 더 빠른 텀을 두고 올라올 수 있도록 노력하겠습니다. 그럼 다음 강좌에서 뵈어요~


|

No7Do's Blog is powered by Daum & tistory