2007/10/30 19:53

출처 :Michael's Blog

Security and Ajax.NET Professional

PostedFriday, May 12, 2006 3:51 PMbyinteractive

I have written a short example about how to use web forms security with Ajax.NET Professional. The example (C# and VB.NET) is included in the latest version available athttp://www.ajaxpro.info/. Discuss the security.aspx example atGoogle groups. (Update: there are about 2.500 members reading and writing posts!!!)

See this example:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Security.Permissions;

public partial class SecurityCS : System.Web.UI.Page
{
  [AjaxPro.AjaxMethod]
  [PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
  public static string AdminMethod()
  {
    return "Hello Admin!";
  }

  protected void Page_Load(object sender, EventArgs e)
  {
    // Register Ajax.NET methods from this class
    AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxPro.Services.AuthenticationS­ervice));
    AjaxPro.Utility.RegisterTypeForAjax(typeof(SecurityCS));
  }

}

The AuthenticationService lets you sign in and out directly from JavaScript code:

<script type="text/javascript>
AjaxPro.Services.Authentication.Login(username, password, callback);
</script>

If you then access a AjaxMethod without the needed security rights you will get an SecurityException.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/06/08 23:53

ASP.NET AJAX1.0의 Client Reference에 보면addHandler라는 메서드가 있습니다.

이 메서드는 element의 이벤트를 추가해주는 역할인데 자세한 설명은여기를 참고해주세요.

사용법은 간단합니다.

$addHandler(객체, 이벤트명, 이벤트메서드);

객체는 $get("element명") 이고 이벤트명은 click등으로 각 event명을 문자열로 넣고 이벤트메서드(handler)는 추가한 이벤트가

발생할 경우 실행될 메서드입니다. 저렇게 등록을 하고 이벤트메서드는 아래와 같은 형태로 작성하면 됩니다.

 

  <scripttype="text/javascript">

  functionbtnClick(eventElement){

        $get("TextBox2").value = (newDate()).toLocaleString();

   }

  </script>

 

위의 메서드에서는 인자를 하나 받는데요. 이 인자에 event를 일으킨 element에 대한 정보들이 존재합니다.

어떤 정보들이 있는지 알고 싶으신 분들은클릭하세요.

 

$addHandler는 유용하게 사용될 수 있으며 AjaxControl Extender들은 $addHandler메서드를 자주? 사용하고 있습니다.

그런데 한가지 주의할 점이 있습니다.

해당 컨트롤이 UpdatePanel안에서 비동기로 업데이트가 이뤄질 경우 $addHandler에 등록된 이벤트는 사라지게 됩니다.

 

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<htmlxmlns="http://www.w3.org/1999/xhtml">

<headrunat="server">

  <title>Untitled Page</title>

</head>

<body>

  <formid="form1"runat="server">

       <asp:ScriptManagerID="ScriptManager1"runat="server"/>

       <asp:UpdatePanelID="UpdatePanel1"runat="server">

           <ContentTemplate>

              <asp:TextBoxID="TextBox1"runat="server"Width="296px"></asp:TextBox><br/>

              <asp:TextBoxID="TextBox2"runat="server"Width="296px"></asp:TextBox><br/>

              <asp:ButtonID="Button1"runat="server"OnClick="Button1_Click"Text="Button"/>

           </ContentTemplate>

       </asp:UpdatePanel>

  </form>

</body>

</html>

  <scripttype="text/javascript">

   $addHandler($get("Button1"),"click",btnClick);

  functionbtnClick(eventElement){

        $get("TextBox2").value = (newDate()).toLocaleString();

   }

  </script>

위의 코드를 보면 Button1을 클릭하게되면 $addHandler에 등록된 btnClick이 실행되고 TextBox2에 클라이언트의 날짜를 출력합니다.

그리고 Button1의 서버측 이벤트는 서버의 현재날짜를 TextBox1에 출력하는 코드가 있습니다.

위의 예제를 실행하면 첫 실행 즉, 처음 페이지가 로드되면 아주 잘 동작하지만 그 이후 부터는 $addHandler에 등록된 btnClick가

실행되지 않음을 알 수 있습니다.

만일 위의 컨트롤들이 UpdatePanel밖에 존재할 경우 PostBack되면서 첫 동작 이 후에도 아주 잘 동작하게 됩니다.

 

이렇게 되는 이유를 제가 이해한데로 설명을 해드리자면...

컨트롤이 PostBack후 다시 랜더링되면 $addHandler로 해당 이벤트를 다시 등록해줘야만 첫 동작 이 후에도 동작을 하게 됩니다.

비동기 업데이트가 아닌 일반 PostBack의 경우 모든 코드를 다시 서버로 부터 받기 때문에 잘 되는 것이고

UpdatePanel에서 비동기 업데이트가 이뤄질 경우 컨트롤들만 다시 랜더링되기 때문에 두번째 동작부터는 안되게 되는 것 입니다.

 

그럼 어떻게 해결 해야 할까요?? 방법은 여러가지가 있을 수도 있지만 제가 생각한 것은 두가지 방식입니다.

 

1. PostBack이후

ScriptManager.RegisterStartupScript

코드를 사용하여 $addHandler를 등록해준다.

이렇게 할 경우 aspx의 코드에 있는 $addHandler를 빼고 cs파일 Page_Load이벤트에 아래의 코드를 넣어주면 됩니다.

 ScriptManager.RegisterStartupScript(this.Page,this.GetType(),"_addHandler","$addHandler($get(\"Button1\"),\"click\",btnClick);",true);

 

이 방식으로 할 경우 aspx코드에서 변경할 것이 btnClick 메서드의 위치입니다. btnClick를 못찾는다고 할 것 입니다.왜 그런지는 아시죠??

 

2. Button1을 UpdatePanel밖으로 빼고 UpdatePanel의 UpdateMode와 ChildrenAsTriggers 속성을 변경한다.

이 방식은 실제 AJAX 개발할 때 자주 사용됩니다. 한페이지에 두개 이상의 UdpatePanel이 있거나 버튼 같은 클릭을 위한 컨트롤이

UpdatePanel과 UI위치상 멀리 있을 경우에 말이지요... 다른 경우도 있겠지만;;

<asp:UpdatePanelID="UpdatePanel1"runat="server"ChildrenAsTriggers="true"UpdateMode="conditional">

 

위처럼 변경하면 됩니다. 그럼 Button1컨트롤은 서버로 부터 비동기 업데이트될 컨트롤에서 제외되기 때문에 처음 페이지 로드시 등록한

$addHandler의 이벤트는 잘 동작하게 되는 것 입니다.

 

2번째 방법을 사용한 코드입니다.

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<htmlxmlns="http://www.w3.org/1999/xhtml">

<headrunat="server">

  <title>Untitled Page</title>

</head>

<body>

  <formid="form1"runat="server">

       <asp:ScriptManagerID="ScriptManager1"runat="server"/>

       <asp:UpdatePanelID="UpdatePanel1"runat="server"ChildrenAsTriggers="true"UpdateMode="conditional">

           <ContentTemplate>

              <asp:TextBoxID="TextBox1"runat="server"Width="296px"></asp:TextBox><br/>

              <asp:TextBoxID="TextBox2"runat="server"Width="296px"></asp:TextBox><br/>

           </ContentTemplate>

           <Triggers><asp:AsyncPostBackTriggerControlID="Button1"EventName="Click"/></Triggers>

       </asp:UpdatePanel>

       <asp:ButtonID="Button1"runat="server"OnClick="Button1_Click"Text="Button"/>

  </form>

</body>

</html>

  <scripttype="text/javascript">

   $addHandler($get("Button1"),"click",btnClick);

  functionbtnClick(eventElement){

        $get("TextBox2").value = (newDate()).toLocaleString();

   }

  </script>

 

위에서 알려준링크에있는 예제가 제가 말한것 처럼 처음에만 동작하지 않고 아주 잘 되는 이유는 UpdatePanenl의 속성에 답이 있습니다.

처음에 이게 왜 안될까 고민했었는데...기본적이라면 기본적인 이것을 팁이랍시고 올리는 제가 미워요;;

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/06/05 23:27

출처 :MSDN Magazine

지난 12개월간 열대 섬으로 휴가를 다녀왔거나 리얼리티 게임 쇼에 참가하여 인터넷과 떨어져 지낸 경우가 아니라면 AJAX에 대한 내용을 들어 본 경험이 있을 것입니다. 그래도 만약을 위해서 간단한 요약을 준비했습니다.

먼저 AJAX는 Asynchronous JavaScript and XML을 의미하는 머리글자어이며 진정한 혁신을 통해 지금까지는 불가능했거나 실질적으로 구현할 수 없었던 솔루션을 가능하게 하는 것을 목표로 하고 있습니다. AJAX가 무엇으로 구성되어 있는지도 알아야 합니다. AJAX는 그 자체가 하나의 기술은 아니며 JavaScript, CSS(Cascading Style Sheet), DHTML 및 XMLHttpRequest와 같이 몇 년 전부터 있었던 클라이언트 쪽 웹 기술의 강력한 조합을 사용하여 구축한 풍부한 기능을 갖춘 브라우저 응용 프로그램을 나타내는 포괄적인 용어입니다.

현재 사용할 수 있는 브라우저의 상당수는 공통적인 기능을 지원하고 있으며 웹 개발자는 이러한 기능을 활용하여 신속하게 새로 고칠 수 있고 클라이언트에서 많은 양의 작업을 처리하는 대화형 응용 프로그램을 구축할 수 있습니다. AJAX 응용 프로그램은 이러한 기능을 활용하여 데스크톱 응용 프로그램을 사용하는 것과 흡사한 풍부한 기능의 사용자 환경을 제공합니다. 또한 AJAX는 어느 때보다 "혼합" 응용 프로그램을 더 쉽게 개발할 수 있도록 지원합니다. 혼합은 다양한 원본의 정보를 결합한 웹 응용 프로그램을 의미합니다. 예를 들어 Microsoft®Virtual Earth™와 부동산 판매 정보를 결합하여 유용한 부동산 업무 도구를 만들 수 있습니다.

사실 필자는 AJAX가 너무 거대하고 중요하기 때문에 몇 년 안에 사람들에게서 잊혀질 것으로 예상하고 있습니다. 그 이유는 AJAX가 이 업계에서 일하는 모든 사람들에게 흡수되어 일상적으로 수행하는 일의 표준적인 부분이 될 것이기 때문입니다. 지금은 XML나 HTTP 사용을 강조할 필요가 없는 것과 마찬가지 원리입니다.

2005년 9월 Microsoft Professional Developers Conference에서 처음으로 소개된 Microsoft ASP.NET AJAX(이전에는 "Atlas"라고 불림)는 ASP.NET 2.0(ajax.asp.net(영문) 참조)에 많은 새 기능을 추가했습니다. 이러한 기능은 모두 웹 사이트에 AJAX 기반 기능을 손쉽게 추가할 수 있도록 설계되었습니다. 이번 달 칼럼에서는 ASP.NET AJAX의 몇 가지 핵심 기능을 자세하게 살펴보고자 합니다. 이 칼럼에서는 독자가 기본 개념 및 도구에 어느 정도 익숙하다고 가정합니다. 처음 시작하는 독자는 Matt Gibbs가MSDN®Magazine2006년 7월호에 소개한 "Atlas at Last: ASP.NET Atlas를 활용한 AJAX 방식의 사이트 개발"을 참조하십시오. 또한 보충 기사인 "현재로서는 동기만 지원" 부분에서도 약간의 추가 정보를 볼 수 있습니다.


ASP.NET에서 AJAX로

AJAX를 사용하여 어떤 새로운 응용 프로그램 기능을 만들 수 있을까요? 좀 더 구체적으로 말해, 비동기 JavaScript 호출 및 브라우저의 개체 모델을 사용하여 어떤 기능을 만들 수 있을까요? AJAX의 기능을 가능하게 하는 기술로는 원격 메서드 호출, 클라이언트 쪽 데이터 바인딩 및 시각 효과의 세 가지가 있습니다. 원격 메서드 호출은 다소 막연하게 들리므로 부분 페이지 다시 게시 및 대역 외 요청으로 범위를 좁히겠습니다.

어떻게 하면 새로운 또는 기존 ASP.NET 응용 프로그램을 AJAX 응용 프로그램으로 바꿀 수 있을까요? 현재 AJAX 개발을 위한 100종 이상의 프레임워크가 있는 것으로 보고되고 있습니다. 이러한 프레임워크에서는 다양한 플랫폼을 지원하며 여러 가지 프로그래밍 방식을 활용합니다. 필자는 일반적으로 AJAX 프레임워크를 기능에 따라 콜백 프레임워크, UI 프레임워크 및 종합 프레임워크의 세 가지 큰 범주로 구분합니다.

콜백 프레임워크는 간단한 클라이언트 및 서버 라이브러리 집합으로 구성됩니다. 클라이언트에서 서버 쪽 코드 조각을 호출하고 serialize된 형식으로 입력 및 출력 매개 변수를 전달하는 것이 이 프레임워크의 기능입니다. 일반적인 UI 프레임워크는 고급 표, 차트 및 트리 컨트롤을 제공하던 기존의 전문 컨트롤 라이브러리를 발전시킨 것이며 비동기 다시 게시 및 페이지의 자동 새로 고침을 위해 클라이언트에 JavaScript 코드를 삽입하는 작업을 지원합니다. 마지막으로 종합 프레임워크는 컨트롤 및 응용 프로그램 서비스를 포함하는 풍부한 기능의 프로그래밍 모델을 제공하며 클라이언트 및 서버 양쪽에 대해 지원되는 경우가 많습니다. Microsoft ASP.NET AJAX는 이 세 번째 범주에 속합니다.

이미 시판된 컨트롤 제품군을 사용하고 있다면 매끄럽게 다음 AJAX 지원 버전으로 업그레이드할 수 있을 것입니다. 응용 프로그램 전체를 내부에서 개발하고 프레젠테이션 계층을 비롯하여 백 엔드 계층까지 처리한다면 종합 프레임워크가 가장 적합한 옵션입니다. 마지막으로 간단한 프레임워크는 기존 ASP.NET 버전 1.1 및 2.0 응용 프로그램에 신속하게 콜백 기능을 추가하려는 경우에만 유용합니다.

ASP.NET 2.0에서는 이미 스크립트 콜백 API를 기본 제공하며 이에 대해서는 "Cutting Edge: Script Callbacks in ASP.NET(영문)" 및 "Cutting Edge: Custom Script Callbacks in ASP.NET(영문)" 칼럼에서 몇 차례 살펴본 적이 있습니다. 그리고 이 칼럼과 함께 제공되는 코드에도 원격 메서드 호출을 위한 매우 간단한 AJAX 프레임워크 데모가 포함되어 있습니다. 이 데모는 단지 50줄의 JavaScript 및 관리 코드로 이루어져 있습니다. 물론 이 데모로 ASP.NET AJAX와 경쟁할 수는 없겠지만 ASP.NET 1.1 응용 프로그램에 기본적인 AJAX 기능을 추가하기 위한 핵심 코드로 사용할 수는 있습니다.


ASP.NET AJAX로의 지름길

ASP.NET AJAX는 서로 배타적이지는 않지만 별개인 클라이언트와 서버의 두 API로 구성되어 있습니다. 개발자는 직접적인 클라이언트 쪽 프로그래밍, 일반적인 서버 쪽 프로그래밍 또는 이 두 가지의 모든 조합을 사용하여 AJAX 기능을 작성할 수 있습니다. 모든 AJAX 기반 페이지에는 브라우저 DOM(문서 개체 모델) 및 응용 프로그램별 확장 기능을 처리하기 위한 약간의 클라이언트 쪽 JavaScript 코드가 필요합니다. 그러나 이러한 스크립트 코드를 작성하는 역할을 ASP.NET 프로그래머에게 넘길 필요는 없습니다. 프레임워크를 사용하면 서버 쪽 컨트롤의 출력을 통해 맞춤형 스크립트 코드를 생성할 수 있기 때문입니다. 이러한 형식의 간접 페이지 업데이트는 새로운 또는 기존 ASP.NET 2.0 페이지에 AJAX 기능을 추가하는 가장 간단한 방법입니다. ASP.NET AJAX에서 페이지 업데이트는 서버 컨트롤인 UpdatePanel 컨트롤이 자동으로 주입한 클라이언트 코드 조각에 의해 제어될 수 있습니다.

UpdatePanel 컨트롤은 ASP.NET AJAX의 서버 중심 프로그래밍 모델에서 중추 신경이라 할 수 있으며 이를 통해 서버 쪽 코드를 실행하고 업데이트된 태그를 클라이언트 브라우저로 반환할 수 있습니다. 이것이 기존의 다시 게시와 어떻게 다른지 궁금할 것입니다. 차이점은 다시 게시가 구현되는 방법에 있습니다. UpdatePanel 컨트롤은 전체 페이지를 새로 고치지 않고 우선 새로운 태그를 위한 대역 외 요청을 전송한 다음 응답이 준비되면 DOM 트리를 업데이트할 수 있습니다.

ASP.NET의 클라이언트 중심 프로그래밍 모델은 원격 끝점(대부분 ASP.NET 웹 서비스 및 Windows®Communication Foundation 서비스)에 대한 호출을 수행할 수 있는 기능을 중심으로 구성되어 있습니다. 클라이언트 브라우저에서 직접 시작된 원격 끝점에 대한 호출에는 JavaScript 프록시 및 약간의 JavaScript 코드가 필요합니다. 마지막으로 클라이언트 쪽 데이터 바인딩은 기존의 JavaScript 런타임 및 DOM을 확장한 것으로 볼 수 있습니다. 순수한 클라이언트 쪽 프로그래밍 스타일의 경우 원격 끝점에 연결하고 데이터를 다운로드한 다음 이를 DOM 하위 트리에 바인딩합니다. 템플릿의 구조는 약간의 상태 정보와 함께 클라이언트에 유지되며 원시 데이터만 서버에서 클라이언트로 전송됩니다.

ASP.NET AJAX에는 세 가지 주요 프로그래밍 방식이 있습니다.그림 1에서는 이러한 도구를 요약하고 최적의 용도를 보여 줍니다.


UpdatePanel 및 인터셉터 패턴

UpdatePanel 컨트롤의 등장으로 인해 페이지 전체를 새로 고치지 않고, 클라이언트 쪽 프로그래밍을 사용하지도 않으면서 페이지 내용을 업데이트하는 프로그래밍 스타일이 가능해졌습니다. ASP.NET AJAX 용어로는 이를 부분 렌더링이라고 합니다. 이러한 기능을 가능하게 하는 구성 요소 중 가장 눈에 띄는 것은 UpdatePanel 컨트롤이지만 부분 렌더링 내부 구현의 실제 처리 주체는 ScriptManager 컨트롤입니다. 물론 UpdatePanel 컨트롤을 무시할 수는 없습니다. 이는 개발자가 부분 업데이트 가능한 페이지를 작성할 때 사용하는 주요 도구입니다.

웹 페이지를 새로 고치는 작업은 제출 단추를 직접 클릭하거나 프로그래밍 방식으로 DOM 폼 개체의 제출 메서드를 호출하는 두 가지 방법 중 하나로 수행할 수 있습니다. 두 경우 모두에서 브라우저는 현재 페이지에 대한 작업을 멈추고 새 요청을 백 엔드 웹 서버로 전송합니다. 그러면 들어오는 응답이 기존 내용을 다시 정의하게 됩니다.

UpdatePanel 컨트롤의 목적은 간단히 말해 이 프로세스에 관여하는 것입니다. 즉, 폼 제출을 가로채어 전송되는 정보를 캡처하고 동일한 정보를 XMLHttpRequest 기반의 대역 외 호출을 통해 전송합니다. 이때 UpdatePanel 컨트롤은 서버에서 처리하여 렌더링될 컨트롤이 무엇인지 나타내는 약간의 정보를 추가합니다. 즉, 부분 페이지 렌더링을 수행하는 것입니다.

UpdatePanel 컨트롤의 결과 동작은 인터셉터 패턴으로 완전하게 설명할 수 있습니다. 여기서 패턴은 개체 호출을 감시하고 자체 코드를 호출자와 수신자 사이에 끼워 넣는 모든 외부 구성 요소를 말합니다. 외부 구성 요소는 이 방법으로 작업을 완벽하게 제어하고 작업이 수행되는 방법을 결정하며 호출자에 유효한 응답을 반환할 수 있게 됩니다.그림 2에서는 ASP.NET AJAX에서 이 패턴이 어떻게 구현되는지 보여 줍니다.

사용자 삽입 이미지

그림 2 UpdatePanel 컨트롤 및 인터셉터 패턴 (더 작게 보려면 이미지를 클릭하십시오.)

클라이언트 페이지로 주입된 스크립트 코드는 폼의 onsubmit DOM 이벤트에 대한 처리기를 등록합니다. 이 새 처리기는 XMLHttpRequest를 통과하고 추가 정보를 전달하는 요청으로 기존의 요청을 대체합니다. 특히 이 처리기는 기존 입력 필드의 목록을 다시 게시하는 역할을 하는 UpdatePanel 컨트롤의 이름을 추가합니다. 페이지로 나눌 수 있는 표 형태가 있는 페이지의 경우 내용이 다음과 같이 수정됩니다.

ScriptManager1=UpdatePanel1|GridView1&
__EVENTTARGET=GridView1&
__EVENTARGUMENT=Page%241&
__VIEWSTATE=...&
__VIEWSTATEENCRYPTED=&
__EVENTVALIDATION=...

의사 매개 변수인 ScriptManager는 다시 게시를 수행하는 UpdatePanel 컨트롤의 ID를 참조합니다. 지정된 UpdatePanel 컨트롤과 연결된 컨트롤만 새로 고쳐지며 수정된 태그는 업데이트된 viewstate 정보와 함께 브라우저로 다시 전송됩니다.

내부 구현 방식에는 차이가 있지만 부분 렌더링은 다양한 AJAX 프레임워크의 공통적인 기능입니다. 각 프레임워크의 차이점은 대부분 업데이트 가능 컨트롤을 요청에 연결하는 방식에 있습니다. ASP.NET AJAX에서는 업데이트 가능 컨트롤이 가장 바깥쪽 컨테이너 컨트롤(UpdatePanel)로 그룹화됩니다. 컨테이너에 포함된 모든 내용은 현재 표시된 페이지의 변경된 내용을 나타내는 태그로 렌더링됩니다. AJAX 스타일의 다시 게시로 렌더링을 수행하는 프레임워크에 프로그래밍 방식으로 개별적인 컨트롤을 등록하도록 요구하는 다른 방법도 있습니다. 이것은 ASP.NET 2.0에서 컨트롤 상태를 지원하는 컨트롤을 사용할 때 진행되는 방식과 다소 유사합니다.

컨테이너에 컨트롤을 그룹화하는 것보다 세분성과 유연성이 개선된 방식으로, 각 컨트롤이 AJAX 스타일의 다시 게시를 렌더링하는 방법을 결정하도록 하는 것이 있습니다. 그러나 이 방법을 사용하면 추가 코드 숨김 명령이나 특수 컨트롤을 사용해야 합니다. 이 방식은 컨트롤 라이브러리 및 기타 제품으로는 좋지만 ASP.NET과 같은 웹 프레임워크로는 지나치게 복잡합니다.

UpdatePanel 컨트롤은 System.Web.UI.Panel에서 파생된 클래스입니다. 하위 ASP.NET 컨트롤의 UI 없는 컨테이너인 UpdatePanel은 어떤 ASP.NET 서버 컨트롤도 포함할 수 있으며 이를 사용하기 위해 특수한 AJAX 지원 컨트롤이 필요하지도 않습니다. UpdatePanel을 사용하면 기존의 ASP.NET과 동일한 응용 프로그래밍 모델 및 프로그램 스타일을 사용하여 완전히 서버에서 AJAX 프로그래밍을 수행할 수 있습니다. 개발자는 JavaScript 또는 클라이언트 쪽 Microsoft AJAX 라이브러리에 대해 배울 필요가 없으며, XML 스크립트 또는 브라우저의 DOM을 사용할 필요도 없습니다.

기존 ASP.NET 페이지를 AJAX 페이지로 변환하려면 두 가지 단계를 거치게 됩니다. 우선 ScriptManager 컨트롤을 페이지에 추가합니다. 그런 다음 부분적 및 비동기적으로 새로 고칠 컨트롤 그룹을 UpdatePanel 컨트롤로 래핑합니다. UpdatePanel 컨트롤은 중첩 시나리오를 지원하며 동적으로 만들 수 있습니다. ASP.NET 페이지에는 원하는 만큼 UpdatePanel 컨트롤을 추가할 수 있습니다.

실제 업데이트는 자식 컨트롤이 다시 게시할 때와 특정 외부 이벤트가 발생할 때의 두 가지 방법으로 트리거됩니다. 트리거와 기타 속성을 사용하면 각 UpdatePanel 컨트롤이 해당 내용을 조건에 따라 새로 고치도록 할 수 있습니다.

UpdatePanel 컨트롤을 사용하면 신속하게 ASP.NET 페이지를 조금씩 AJAX로 마이그레이션할 수 있습니다. 동일한 ASP.NET 페이지에서 AJAX 스타일의 다시 게시 및 기존 방식의 다시 게시를 모두 수행할 수 있으므로 UpdatePanel에서는 각각의 모든 요청에 대해 페이지의 보기 상태를 전달해야 합니다. 보기 상태는 서버로 전송되고 선택된 컨트롤의 변경 내용을 반영하도록 업데이트된 다음 클라이언트에서 다운로드됩니다. 이벤트 유효성 검사 데이터의 경우에도 동일한 과정이 진행됩니다. 보기 상태 및 이벤트 유효성 검사 데이터는 클라이언트에서 업데이트할 수 없으므로 서버로 다시 전송하여 변조 및 올바른 업데이트 여부를 확인해야 합니다. 클라이언트에서 보기 상태 및 이벤트 유효성 검사 데이터의 최신 복사본을 사용할 수 있도록 하는 것은 AJAX 및 기존 스타일 모두에서 성공적인 다시 게시를 허용하면서도 페이지를 일관적인 상태로 유지하는 데 매우 중요합니다.

기본적으로 UpdatePanel은 ASP.NET AJAX를 배우기 위한 가장 쉬운 방법이며 이를 사용하면 최소한의 업그레이드와 마이그레이션 작업만으로 기존 페이지 및 AJAX 페이지에서 완벽하게 상호 운용이 가능합니다. 업데이트 가능한 패널을 사용하면 패널이 매우 빠르게 새로 고쳐집니다. 사실 이러한 업데이트는 너무 빠르게 수행되어 사용자가 변화를 알아차리지 못하는 경우도 있습니다. 이 때문에 변화하는 상황에 대해 알려 주는 자주 변경되는 패널에는 적당하지 않을 수 있습니다. UpdateProgress 컨트롤과 같이 내용이 자주 변경되는 패널은 표시된 변경 내용을 사용자에게 알려 주는 용도가 아니라 장기 작업에 맞게 최적화되어 있습니다. 이러한 변경 내용에 대해 사용자에게 피드백을 제공하는 데는 AJAX Control Toolkit의 최신 CTP에 정의되어 있는 UpdatePanelAnimation Extenter를 사용하는 것이 좋습니다.여기(영문)에서 작동하는 샘플을 볼 수 있습니다. 이 Extender는 다시 게시하는 동안 UpdatePanel의 영역에 애니메이션을 적용합니다. Extender에서는 특히 updating 및 updated 이벤트에 대한 애니메이션을 지정할 수 있습니다. AJAX Control Toolkit은 ASP.NET AJAX Extensions 다운로드에는 통합되어 있지 않으므로 별도로 설치해야 합니다.


대역 외 호출 제어

JavaScript를 사용하는 데 익숙하며 클라이언트에서 직접 서버 호출을 수행하려는 개발자의 경우에는 기본적으로 웹 서비스를 사용하거나 정적 페이지 메서드로 호출할 수 있습니다.

개발자는 스크립트 관리자에 ASMX 웹 서비스를 등록함으로써 JavaScript 프록시 클래스를 생성하고 이를 클라이언트 페이지에 주입하도록 ASP.NET AJAX 인프라에 지시하게 됩니다. 웹 서비스 URL에 /js 접미사를 붙여 주소 표시줄(로컬 시스템)에 입력하면 프록시 클래스를 살펴볼 수 있습니다. 다음은 공용 메서드 두 개가 있는 웹 서비스를 위한 JavaScript 프록시의 예입니다. 코드는 읽기 쉽게 간소화하였습니다.

Type.registerNamespace('Samples.MyWebService');
Samples.MyWebService = new function() {
this.appPath =http://YourServer/AjaxDemo/;
var cm = Sys.Net.ServiceMethod.createProxyMethod;
cm(this, "LookupCustomer", "id");
cm(this, "LookupAllCustomers");
}

이 코드를 사용하면 스크립트 태그에서 웹 서비스를 호출할 수 있습니다. 여기에서는 기존 프록시 패턴이 사용되며 전반적인 메커니즘은 기존 ASP.NET 또는 Windows 응용 프로그램의 서버에서 웹 서비스를 사용할 때와 정확하게 동일합니다.

그러나 몇 가지 주의 사항이 있습니다. 클라이언트에서 어떤 종류의 서버 쪽 코드를 호출하는 것인지, 다른 말로 하면 클라이언트에서 웹 서비스의 어떤 작업을 호출하려는 것인지 생각해 보아야 합니다. AJAX 페이지에서 호출되는 웹 서비스는 클라이언트 페이지에 약간의 비즈니스 논리를 노출하게 됩니다. 공개 끝점은 인터넷에서 호출할 수 있는 웹 서비스이며 응용 프로그램의 논리를 보호하기 위한 기본 제공 보안 계층은 없습니다. 이러한 취약성은 이전부터 있었던 것입니다.

ASP.NET AJAX는 개발자에게 웹 서비스를 통해 약간의 응용 프로그램 논리를 공개할 수 있는 기회를 제공합니다. 일단 인터넷에 게시되면 모든 호출자가 이 논리(어떤 보안 계층으로도 보호되지 않음)를 사용할 수 있습니다. 일반적으로 인터넷에서 사용하기에 안전한 것으로 생각되는 데이터 및 논리만 공개해야 합니다. 제품 목록을 반환하는 웹 서비스를 작성하고 호출하더라도 심각한 문제는 일어나지 않을 것입니다. 그러나 예를 들어 신용 카드 유효성 검사 처리를 포함하는 BLL(비즈니스 논리 계층)을 공개하는 것은 피해야 합니다.

ASP.NET AJAX는 웹 서비스를 사용하여 클라이언트 페이지에서 직접 사용할 BLL을 공개하도록 하고 있습니다. 즉, AJAX 웹 서비스는 중요하지 않은 사용자 인터페이스 계층 BLL의 한 종류로 보면 됩니다. 중요한 BLL은 기존의 다시 게시 또는 UpdatePanel 컨트롤을 사용하여 호출해야 합니다.

웹 서비스를 직접 ASP.NET AJAX 페이지에 연결하려면 이러한 웹 서비스가 호출자 페이지와 동일한 웹 응용 프로그램에서 호스팅되는 로컬 웹 서비스여야 합니다. 이러한 요구 사항이 있는 이유는 두 가지입니다. 첫째, 웹 서비스는 각 요청에 추가된 /js 접미사를 처리하는 방법을 아는 ASP.NET AJAX 응용 프로그램의 지원을 받아야 합니다. 다른 ASP.NET AJAX 응용 프로그램을 사용하여 웹 서비스를 호스팅하는 것도 가능하지만 이 경우에는 클라이언트 호출이 사이트 간 호출을 방지하는 최신 브라우저의 엄격한 보안 설정과 충돌할 수 있습니다.


페이지 메서드 대 웹 서비스 메서드

서버 코드를 ASP.NET AJAX 페이지에 바인딩하는 또 다른 방법으로 페이지 메서드를 호출하는 방식이 있습니다. 호출 가능한 페이지 메서드는 코드 숨김 클래스에 정의되며 웹 서비스 메서드에 사용된 것과 동일한 WebMethod 특성이 지정된 공용 정적(Visual Basic®.NET에서는 공유) 메서드입니다. 현재로서는 인라인 및 코드 숨김의 경우 모두 ASPX 페이지에서만 사용할 수 있지만 향후에는 사용자 컨트롤 및 사용자 지정 컨트롤로 확장될 것입니다.

ASMX 웹 서비스와 페이지 메서드에는 다른 설정이 필요하다는 것도 알아야 합니다. 특히 페이지 메서드를 실행하려면 스크립트 관리자에 웹 서비스를 등록하고 스크립트 HTTP 모듈을 설치해야 합니다.그림 3에서는 web.config 파일에 무엇이 필요한지 보여 줍니다.

웹 서비스를 등록하고 프록시 생성을 지정하려면 다음과 같은 항목이 필요합니다.

<asp:ScriptManager ID="scriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/WebServices/MyDataService.asmx" />
</Services>
</asp:ScriptManager>

웹 서비스 클래스에 지정할 추가 특성도 필요합니다. 특히 JavaScript 프록시 클래스 생성을 위해 ScriptService 특성이 필요하며 일반 형식을 제외한 사용하려는 각 사용자 지정 형식에 대해 GenerateScriptType이 필요합니다.그림 4에서 예를 볼 수 있습니다.

Customer 형식에는 GenerateScriptType을 적용해야 하지만 CustomerCollection의 경우 이 형식은 ASP.NET AJAX 기본 제공 지원이 있는 제네릭 컬렉션<T> 클래스에서 파생되기 위해 정의된 것이므로 적용하지 않습니다.

public class CustomerCollection : Collection<Customer> {}

페이지 메서드에 필요한 HTTP 모듈은 ASPX 요청을 위한 기본 HTTP 처리기에 연결한 다음, 지정된 메서드를 실행하고 반환 값을 serialize하는 사용자 지정 코드 조각으로 렌더링 단계를 재지정합니다.

페이지 메서드 방식과 웹 서비스 메서드 방식은 모두 백 엔드 BLL에 액세스할 수 있도록 도와줍니다. 공개적으로 제공되는 웹 서비스 메서드와 마찬가지로 페이지 메서드 역시 기초적인 JSON(JavaScript Object Notation) 기술만 있으면 브라우저의 주소 표시줄에서 손쉽게 자동화할 수 있습니다. 따라서 공개하는 BLL 논리와 관련하여 WebMethod와 마찬가지로 이러한 페이지 메서드에 대해서도 주의를 기울여야 합니다.

결국 페이지 메서드 또는 웹 서비스 메서드 중에 어떤 것을 사용할지는 순전히 개발자의 선호에 달려 있습니다. 두 가지 경우에 모두그림 5와 같이 적절한 BLL 함수로 라우팅되는 Façade 계층으로 호출해야 합니다. 웹 서비스 메서드는 각 페이지에 서비스로의 끝점을 등록했다는 가정하에 어떤 페이지에서도 호출할 수 있으나 페이지 메서드는 이를 정의한 페이지에서만 호출할 수 있습니다. 현재 필자는 페이지 메서드를 사용하는 방법을 선호하고 있습니다.

사용자 삽입 이미지

그림 5 페이지 메서드 및 웹 서비스 메서드 비교 (더 작게 보려면 이미지를 클릭하십시오.)

ASP.NET AJAX 웹 서비스 메서드와 페이지 메서드는 모두 개체 데이터를 전달하기 위해 JSON을 광범위하게 사용합니다. 간단한 데이터 교환 형식인 JSON은 개체를 serialize하여 문자열로 만드는 데 사용됩니다. JSON은 근본적으로 단순하므로 사용자와 시스템 모두에 적절합니다. SOAP 패킷을 읽고 쓰는 것보다는 JSON 문자열을 읽고 쓰는 것이 쉽습니다. 또한 JSON은 시스템에서 구문 분석하고 처리하기도 쉽습니다.

페이지 메서드가 웹 메서드에 비해 좋은 성능을 제공할 것으로 기대하는 개발자도 있을 것입니다. 결국 웹 서비스 호출을 확인하기 위해 ASP.NET 런타임은 SOAP 패킷을 구문 분석해야 하기 때문입니다. 그러나 실제로는 그렇지 않습니다. ASP.NET AJAX는 모든 ASMX 요청을 가로채는 맞춤형 HTTP 처리기를 설치합니다(그림 3참조). /js 접미사가 있는 요청은 JSON 페이로드 및 웹 서비스 메서드와 직접 작업하여 다르게 처리됩니다. 결과적으로 SOAP는 전혀 관련되지 않으며 요청의 본문에는 입력 인수의 JSON 스트림만 포함하게 됩니다. AJAX가 아닌 요청의 경우 새 HTTP 처리기는 SOAP를 이해할 수 있는 원래 ASP.NET 처리기로 호출을 위임합니다.


ASP.NET AJAX 적용 방법

모든 사항을 고려할 때 필자는 UpdatePanel이 대부분의 개발 팀에 최적의 방식이라고 생각합니다. 이 방법을 사용하면 기존 ASP.NET이 방해를 받지 않으며 필요에 따라 기존 페이지를 수정할 수 있습니다. 또한 복잡하지 않고 시작하기 전에 많은 내용을 새로 배울 필요도 없습니다. 뿐만 아니라 UpdatePanel은 BLL에 대해서도 기존 웹 페이지와 같이 어느 정도 수준의 보호를 제공하며 긴 작업을 실행하는 비동기 ASP.NET 페이지를 완벽하게 지원합니다.

마지막으로 강조하고 싶은 것은 다양한 AJAX 플랫폼을 혼합하지 않도록 해야 한다는 것입니다. JavaScript 기본 제공 개체 확장이라는 측면에서 ASP.NET AJAX 및 다른 프레임워크 간에 충돌이 발생할 수 있습니다. 더 중요한 것은 현재 동작하는 제품 조합이 나중에도 동작하리라는 보장은 없다는 사실입니다. 특정 프레임워크의 새 버전에서는 이전에는 없던 충돌이 발생할 수 있습니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/06/05 23:08

출처 :MSDN Magazine

 

좋든 나쁘든, UpdatePanel 컨트롤은 ASP.NET AJAX 커뮤니티의 가장 주된 화두입니다. 좋은 이유는 UpdatePanel를 사용할 경우 부분 페이지 렌더링이 무척 쉬워지기 때문이고, 나쁜 이유는 단순성과 용이성으로 인해 효율성이 떨어질 뿐만 아니라 아이러니하게도 대역폭 손실이 발생하기 때문입니다.

UpdatePanel이 일반 웹 페이지에 AJAX의 기능을 이용할 수 있게 해 주긴 하지만 우리가 보통 AJAX에서 기대하는 효율성을 자동으로 가져다 주지는 않습니다. 예를 들어UpdatePanel 컨트롤이 서버의 콘텐츠를 업데이트하기 위해 서버를 대상으로 비동기 AJAX 콜백을 수행할 때 보기 상태를 비롯하여 일반적인 ASP.NET 포스트백에 포함되는 모든 항목이 요청에 포함된다는 사실을 알고 계십니까?대부분의 개발자는 AJAX를 사용하면 보기 상태가 필요 없다고 생각합니다. 그러나 AJAX의 UpdatePanel에 있어서는 예외입니다.

UpdatePanel 컨트롤을 사용하려면 그 결과에 대해 알아야 합니다. 성능의 관점에서 보면 응용 프로그램에 UpdatePanel을 사용하는 대신 웹 메서드나 페이지 메서드에 대한 비동기 호출을 사용하는 것이 더 나은 경우가 많습니다. 이렇게 하면 회선을 통해 전송되는 데이터의 양이 10배 이상 감소됩니다. 개발자가 페이지에 JavaScript를 사용하여 UI 업데이트를 명시적으로 처리해야 하는 경우 기본적으로 웹 메서드나 페이지 메서드에 대한 비동기 호출을 사용하도록 전환해야 합니다.

또한 ASP.NET AJAX 토론 포럼은 이미 UpdatePanel 사용자 지정에 대한 질문으로 넘치고 있습니다. 그 중에는 Microsoft®AJAX 라이브러리의 JavaScript 클래스로, 클라이언트 측 UpdatePanels 지원을 제공하는 PageRequestManager만 이해하면 궁금증이 해결되는 경우가 많습니다.

ASP.NET AJAX가 제공되는 데 발맞춰 사용자 지정 방법, 최적화 방법 등 UpdatePanel에 대해 이 칼럼을 통해 좀 더 자세히 알아보겠습니다.


주요 업데이트

 

Microsoft의 개발자가 불쌍하게 여겨질 때가 있습니다. 일을 제대로 못하면 대중의 질타를 받기가 십상이기 때문이죠. 그리고 가끔은 너무 일을 잘해서 질타를 받는 경우도 있습니다. 예를 들어 최근에 필자는 한 고객으로부터 ASP.NET AJAX UpdatePanel이 너무 잘 작동한다고 불평하는 전자 메일을 받았습니다.

UpdatePanel을 사용하면 ASP.NET 페이지가 서버에 포스트백될 때 나타나는 깜박임 현상을 손쉽게 해결하여 깜박임 없이 원활하게 업데이트가 이루어지도록 할 수 있습니다. UpdatePanel은 포스트백을 비동기 콜백(XML-HTTP 요청)으로 변환하고 클라이언트에서 JavaScript를 사용하여 UpdatePanel 컨트롤로 캡슐화된 페이지의 일부를 새로 고치는 방식으로 작동합니다. 그러면 브라우저에서 포스트백을 수행하는 동안 페이지를 다시 그리지 않으므로 깜박임 현상이 사라집니다.

고객이 불평한 내용은 페이지 중 일부가 새 콘텐츠로 업데이트되었다는 사실을 사용자가 알아채지 못할 수도 있다는 것이었습니다. 그 고객은 "고객이 중요한 업데이트를 놓치지 않도록 ASP.NET AJAX 팀에서 UpdatePanel이 약간만 깜박이도록 만들 수는 없느냐"고 물어왔습니다.

안타깝게도 ASP.NET AJAX 팀은 UpdatePanel이 깜박이도록 만들 생각이 아마 없을 겁니다. 애초에 UpdatePanel을 개발한 이유가 깜박임을 없애는 것이었으니까요. 그러나 좋은 소식도 있습니다. 브라우저에서 약간의 AJAX 작업만 하면 업데이트된 UpdatePanel로 사용자의 주의를 끌 수 있습니다. 비법은 바로 Microsoft AJAX 라이브러리(ASP.NET AJAX의 절반을 구성하는 JavaScript 클래스의 라이브러리)의 Sys.WebForms.PageRequestManager 클래스를 사용하는 것입니다. PageRequestManager는 UpdatePanel에 의해 실행되는 비동기 콜백을 관리할 뿐만 아니라 비동기 콜백이 완료되면 UpdatePanel의 콘텐츠를 업데이트하는 역할도 담당합니다.

PageRequestManager는 업데이트가 발생하기 전후에 브라우저에서 이벤트를 발생시킵니다. JavaScript에서 이러한 이벤트를 연결하고 업데이트된 콘텐츠로 사용자의 주의를 끄는 코드를 실행할 수 있습니다. 이때 핵심이 되는 이벤트는 pageLoaded인데, 이 이벤트는 브라우저에 페이지가 로드될 때마다 발생합니다(ASP.NET의 Page_Load에 해당). 또한 UpdatePanel 컨트롤을 대신하여 실행된 비동기 콜백이 완료되거나 UpdatePanel의 콘텐츠가 업데이트될 때마다 발생합니다. 다음 코드 두 줄로 pageLoaded 이벤트에 대한 JavaScript 처리기를 등록할 수 있습니다. 이 두 줄의 코드는 한 줄로 합칠 수도 있습니다.

var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_pageLoaded(pageLoaded);

이 코드의 첫째 줄에서는 페이지의 PageRequestManager 개체에 대한 참조를 가져옵니다. 그리고 둘째 줄에서는 pageLoaded라는 JavaScript 함수를 pageLoaded 이벤트의 처리기로 등록합니다.

pageLoaded 이벤트 처리기가 호출되면 역시 Microsoft AJAX 라이브러리의 클래스 중 하나인 Sys.WebForms.PageLoadedEventArgs 형식의 인수를 받습니다. PageLoadedEventArgs에는 콘텐츠가 업데이트된 모든 UpdatePanel을 열거하기 위해 호출할 수 있는 get_panelsUpdated 메서드가 포함되어 있습니다. 기본적으로 UpdatePanel은 JavaScript를 사용하여 DIV를 깜박이거나 강조 표시하거나, 또는 사용자의 주의를 끄는 다른 효과를 구현하는 클라이언트 측 DIV에 지나지 않습니다.

그림 1에 나열된 코드는 pageLoaded 이벤트를 사용하여 업데이트를 강조하는 한 가지 방법을 보여 줍니다. 이 JavaScript는 업데이트가 발생할 때마다 업데이트된 UpdatePanel을 나타내는 DOM(문서 개체 모델) 요소를 세 번 연속으로 빠르게 표시했다가 사라지도록 하여 깜박입니다. 이러한 깜박임은 깜박임 횟수를 입력 매개 변수로 사용하는 flashPanels라는 도우미 함수에 의해 수행됩니다.

다음으로 업데이트된 UpdatePanel을 반복적으로 표시하고 숨겨 깜박임 효과를 만드는 방법을 살펴보겠습니다. 이 코드에서는 DOM 요소와 직접 상호 작용하는 대신 UpdatePanel을 나타내는 DOM 요소를 Sys.UI.Control 개체로 래핑합니다. 그리고 Sys.UI.Control의 set_visible 및 get_visible 메서드를 사용하여 표시하거나 숨깁니다.

_panels[i].set_visible(!_panels[i].get_visible());

Sys.UI.Control은 Microsoft AJAX 라이브러리(MicrosoftAjax.js)에 포함된 JavaScript 클래스입니다. 이 방법으로 표시 여부를 전환하면 브라우저 종류에 관계없이 효과를 구현할 수 있다는 장점이 있습니다. 이는 ASP.NET AJAX를 지원하는 모든 브라우저(현재 사용되는 거의 모든 브라우저)에 동일하게 적용됩니다. 반면 브라우저 DOM과 직접 상호 작용하는 JavaScript 코드의 경우 다른 종류의 브라우저에서 사용하려면 코드를 수정해야 합니다.


UpdatePanel 업데이트 취소

 

pageLoaded 이벤트는 콘텐츠를 업데이트하기 위해 UpdatePanel을 서버로 다시 보낼 때 PageRequestManager 클래스에 의해 발생하는 몇 가지 이벤트 중 하나입니다. PageRequestManager가 발생시키는 다른 중요한 이벤트로는 비동기 콜백이 발생하기 전에 실행되는 initializeRequest가 있습니다.

최근에 AsyncPostBackTrigger가 UpdatePanel 업데이트를 트리거할 수 있을지 여부를 런타임에 결정할 수 있는가에 대해 질문을 받았습니다. 대답은 "가능하다"입니다. 이를 위해서는 initializeRequest 이벤트를 처리하면 됩니다.

initializeRequest 처리기에 전달되는 두 번째 매개 변수는 initializeRequestEventArgs 형식의 개체입니다. 이 개체에는 업데이트를 트리거한 단추나 기타 요소를 식별하는 get_postBackElement 메서드와 콜백이 발생하기 전에 취소하는 데 사용할 수 있는 set_cancel 메서드가 들어 있습니다. 다음은 set_cancel 메서드의 실제 사용 예입니다.

<script type=”text/javascript”>
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(initializeRequest);
function initializeRequest(sender, args) {
args.set_cancel(!confirm(‘Are you sure?’));
}
</script>

이 예에서 intializeRequest 처리기는 콜백이 실행되기 전에 사용자에게 업데이트를 계속할지를 묻는 확인 대화 상자를 표시합니다. 이 확인 대화 상자에서 취소를 클릭하면 set_cancel에 True 값이 전달되어 콜백이 바로 중지됩니다. 실제 개발 시에는 업데이트를 계속하기 전에 사용자에게 확인 대화 상자를 표시할 필요가 없겠지만 응용 프로그램의 다른 위치에서 상황에 따라 업데이트를 취소할 수 있도록 하면 유용합니다.

또한 비동기 콜백이 실행된 후 완료되기 전에 취소할 수도 있습니다. PageRequestManager는 이러한 기능을 수행하는 abortPostBack 메서드와 비동기 콜백이 보류 상태인지를 확인하는 get_isInAsyncPostBack 메서드를 제공합니다. 이 두 메서드는 UpdateProgress 컨트롤과 함께 취소 UI를 구현하는 데 사용되는 경우가 많습니다.


여러 UpdatePanel

 

하나의 페이지에 여러 UpdatePanel이 포함되어 있을 수 있습니다. 기본적으로 페이지에서 UpdatePanel 중 하나가 업데이트되면 페이지의 다른 UpdatePanel도 업데이트됩니다. 이러한 동작이 필요한 경우도 있겠지만 대개 특정 UpdatePanel에 대한 응답으로 다른 모든 UpdatePanel을 업데이트할 필요는 없습니다.

이 경우 페이지에 있는 UpdatePanel 컨트롤의 UpdateMode 속성을 "Conditional"로 설정하면 업데이트할 UpdatePanel 인스턴스와 업데이트 시점을 선택할 수 있습니다. 그리고 UpdatePanel 중 하나가 업데이트되고 서버 측 이벤트 처리기를 호출할 때 업데이트할 다른 창에 대한 UpdatePanel.Update를 호출합니다. 이 경우 렌더링되는 컨트롤의 수가 적어지므로 서버의 부하가 감소되고, 업데이트하지 않는 UpdatePanel이 응답에 항목을 추가하지 않으므로 응답의 데이터 양이 줄어듭니다.


UpdatePanel을 사용하지 않고 업데이트

 

AJAX는 사용자 환경을 개선할 뿐만 아니라 연결 효율성도 크게 높입니다. 기존에는 ASP.NET 포스트백이 발생하면 보기 상태를 비롯하여 Web form의 모든 데이터가 포스트백을 통해 서버로 전달되었습니다. 보기 상태는 ASP.NET 페이지, 특히 DataGrid 컨트롤과 GridView 컨트롤을 사용하는 페이지의 응답 속도가 느려지는 주된 원인 중 하나입니다. 보기 상태가 너무 많은 페이지는 성능을 저하시키기 때문입니다. 이렇게 보기 상태가 너무 많은 페이지는 ASP.NET 응용 프로그램에서 쉽게 발견할 수 있습니다.

ASP.NET 포스트백을 AJAX 콜백으로 제대로 대체했을 때 기대할 수 있는 이점 중 하나는 AJAX 콜백 시에 필요한 데이터만 전송된다는 점입니다. 다시 말해, 전송에서 보기 상태를 포함하지 않아도 됩니다.

UpdatePanel을 사용하여 페이지에서 깜박임 없이 업데이트를 수행하면 효율성이 높아질 것이라고 기대하게 됩니다. UpdatePanel에는 AJAX가 사용되니까요. 그러나 UpdatePanel이 업데이트될 때 전송 트래픽을 확인해 보면 효율성이 크게 개선되지 않음을 알 수 있습니다. 특히 데이터를 보낼 때 말이죠. 포스트백을 실행하는 동안 일반적으로 서버에 전송되는 보기 상태 데이터를 비롯한 여러 가지 데이터는 UpdatePanel 콜백 시에도 전송됩니다. 사실 UpdatePanel에서 발생하는 비동기 XML-HTTP 요청 시에 업로드되는 데이터는 표준 ASP .NET 포스트백 시에 업로드되는 데이터와 거의 같습니다. 따라서 ASP.NET AJAX에 관한 안타까운 진실은, UpdatePanel은 사용하기 편리하도록 할 뿐이지 전송 효율성과는 관계가 없다는 것입니다.

UpdatePanel의 효율성을 높일 수 있는 방법은 사실상 전무하지만, UpdatePanel을 사용하는 대신 ASP.NET AJAX의 다른 기능을 사용하면 마찬가지로 원활하지만 훨씬 효율적인 방식으로 페이지의 콘텐츠를 업데이트할 수 있습니다. 이 경우 작업이 약간 복잡해지지만 클라이언트와 서버 간에 전송되는 데이터의 양을 크게 줄일 수 있으므로 그만한 가치가 충분하다고 할 수 있습니다.

뿐만 아니라 서버의 부하도 줄일 수 있습니다. UpdatePanel이 서버를 다시 호출하면 콜백 대상 페이지가 전체 수명 주기에 가까운 주기를 반복하게 됩니다. 즉, 페이지가 인스턴스화되면 페이지의 컨트롤이 인스턴스화되고 UpdatePanel에 있는 컨트롤이 일반 렌더링 주기를 경험하게 됩니다. 페이지의 일부만 업데이트하는 데 오버헤드가 너무 많이 발생하게 되는 것입니다.

예를 들어그림 2의 페이지 조각을 살펴보겠습니다. 이 페이지 조각은 사용자가 우편 번호를 입력하고 단추를 클릭하여 시 및 주 필드를 해당 시와 주로 초기화하는 간단한 UI를 제공합니다(그림 3참조). 모든 컨트롤은 UpdatePanel에서 호스팅되므로 Button 컨트롤의 포스트백이 비동기 콜백으로 변환되고 콜백에서 서버의 이벤트 처리기(GetCityAndState)가 호출됩니다. GetCityAndState(코드는 생략)는 ZIP Code TextBox에서 우편 번호를 읽어 시 및 주로 변환하고 해당 정보에 따라 시 및 주를 나타내는 TextBox와 DropDownList를 업데이트합니다. 이러한 모든 프로세스는 UpdatePanel 내에서 수행되므로 업데이트가 깜박임 없이 원활하게 이루어집니다.

사용자 삽입 이미지

그림 3 시, 주 및 우편 번호 UI (더 크게 보려면 이미지를 클릭하십시오.)

그런데 문제가 한 가지 있습니다. 이 방법으로 UpdatePanel을 사용하면 사용자 환경이 개선되지만 전달되는 데이터 양에는 거의 변화가 없습니다. 또한 서버의 부하도 거의 줄지 않습니다. UpdatePanel의 컨트롤이 렌더링될 때까지 서버에서 수행되는 처리 프로세스는 완전한 포스트백의 경우와 거의 동일합니다. GetCityAndState와 같은 서버 측 이벤트 처리기가 비동기 콜백에서도 기존의 포스트백에서와 마찬가지로 작동한다는 점이 UpdatePanel 컨트롤의 장점 중 하나이므로 이는 필연적인 결과입니다. 따라서 페이지의 컨트롤은 인스턴스화되어야 하고, 초기화되어야 하며, 보기 상태에 액세스할 수 있어야 합니다.

그림 4는 UpdatePanel 컨트롤을 사용하지 않고 동일한 기능을 구현하는 방법을 보여 줍니다. 여기서는 Autofill 단추가 GetCityAndState라는 ASMX 웹 메서드에 비동기 XML-HTTP 요청을 보내는 JavaScript 코드에 연결되어 있습니다. 이 호출은 ScriptManager 컨트롤의 서비스 참조에 의해 생성되는 JavaScript 프록시(ZipCodeService)를 통해 전달됩니다. GetCityAndState는 우편 번호 문자열을 입력 받아 두 가지 항목(해당 시와 주)이 포함된 문자열 배열을 반환합니다. 완료 함수 onGetCityAndStateCompleted는 배열에서 이러한 항목을 검색하여 시 및 주 필드에 삽입합니다. 외부에서도 같은 결과가 나타나지만 내부와 실행 방법이 다릅니다.

다음은 JavaScript 프록시를 통한 ASMX 웹 메서드 호출 방법을 보여 주는 코드입니다.

[ScriptService] public class ZipCodeService : System.Web.Services.WebService
{
[WebMethod]
public string[] GetCityAndState(string zip) { ... }
}

속해 있는 클래스가 WebService가 아니라 ScriptService라는 점을 제외하면 이는 표준 웹 메서드에 해당한다고 할 수 있습니다. ScriptService는 WebService와 같지만 클라이언트 측 스크립트에서 웹 서비스의 웹 메서드를 호출할 수 있음을 나타내는 부가적인 의미가 있습니다.

ASP.NET AJAX는 일반적인 웹 메서드가 XML-HTTP 요청의 대상이 되도록 허용할 뿐만 아니라 페이지 메서드라는 특수한 웹 메서드도 지원합니다. 페이지 메서드는 웹 페이지에 구현되는 웹 메서드입니다. 즉, ASMX 파일이 아니라 ASPX 파일 또는 코드 숨김 파일에 작성됩니다. 이러한 페이지 메서드를 사용하면 전용 웹 서비스를 작성하지 않고도 XML-HTTP 콜백에 대한 종단점을 제공할 수 있습니다.

페이지 메서드는 공용 정적 메서드여야 하며 웹 메서드와 마찬가지로 WebMethod 특성이 지정되어야 합니다. 웹 메서드와 페이지 메서드에는 전송되는 데이터를 보다 세부적으로 제어할 수 있는 ScriptMethod 특성도 지정될 수 있습니다. 클라이언트에서 페이지 메서드는 특수한 PageMethods 프록시를 통해 JavaScript에서 호출됩니다.

웹 서비스와 달리 페이지 메서드에는 서비스 참조가 필요 없지만, ScriptManager 컨트롤의 EnablePageMethods 속성을 True로 설정하는 등의 방법으로 페이지 메서드를 활성화해야 합니다.

<asp:ScriptManager ID=”ScriptManager1” runat=”server” EnablePageMethods=”true” />

내부적으로 페이지 메서드는 웹 메서드와 동일한 수준의 효율성을 제공합니다. 즉, 페이지 메서드가 호출될 때 보기 상태와 기타 입력 데이터가 서버로 전송되지 않습니다. 또한 페이지 메서드는 정적이므로 페이지 개체를 인스턴스화하지 않고도 호출할 수 있습니다. 마지막으로 페이지 메서드를 호출하더라도 기존의 ASP.NET 요청에서 트리거되는 페이지 수명 주기가 실행되지 않습니다.


웹 서비스는 SOAP이나 XML과 다르다.

 

ASP.NET AJAX의 가장 중요한 기능 중 하나는 브라우저 클라이언트에서 비동기 XML-HTTP 요청을 사용하여 서버의 웹 메서드와 페이지 메서드를 호출하는 기능입니다. 그러나 다른 사람에게 이 기능에 대해 말할 때는 조금 망설이게 됩니다.

웹 서비스라는 용어를 들으면 대부분 SOAP와 XML을 떠올리게 됩니다. 그런데 SOAP와 XML이라는 용어는 모두 효율성이라는 단어와는 거리가 멉니다. JavaScript에서 ASP.NET AJAX를 사용하여 웹 메서드를 호출할 수는 있지만 ASP.NET AJAX에서 SOAP와 XML은 사용하지 않습니다.

그림 5에는그림 4의 웹 메서드 호출을 실행했을 때 전송되는 항목이 나와 있습니다. HTTP 헤더를 제외하고 이 요청에서 전송되는 유일한 데이터는 사용자가 입력한 우편 번호이며, 응답에서 반환되는 유일한 데이터는 시와 주를 나타내는 문자열 쌍입니다. 이때 SOAP나 XML(또는 보기 상태)은 찾아볼 수 없습니다. 대신 XML보다 훨씬 간단하고 처리하기 쉬운 JSON(JavaScript Object Notation)을 사용하여 입/출력이 인코딩됩니다. 또한 요청과 응답에서는 SOAP 대신 기본적으로 HTTP에 해당하는 간단한 프로토콜을 사용합니다. 이러한 HTTP와 JSON의 조합은 웹 메서드 및 페이지 메서드에 대한 ASP.NET AJAX 호출의 효율성을 기존의 웹 서비스 호출에 비해 크게 높입니다.

JSON은 최신의 업계 표준 직렬화 형식으로, ASP.NET AJAX에서 기본 형식으로 사용됩니다. 클라이언트 측에서의 JSON 직렬화 및 역직렬화 지원은 Microsoft AJAX 라이브러리의 Sys.Serialization.JavaScriptSerializer 클래스를 통해 제공됩니다. 또한 서버의 경우 System.Web.Script.Serialization.JavaScriptSerializer 클래스에 의해 지원됩니다.

JSON을 지원하지 않는 형식도 있습니다. 예를 들어 순환 참조가 있는 개체는 JSON으로 처리할 수 없습니다. JSON을 지원하지 않는 복잡한 데이터 형식을 반환해야 하는 경우 ASP.NET AJAX의 ScriptMethod 특성을 사용하여 반환 형식을 XML로 직렬화할 수 있습니다. 이 기법은 다음과 같이 XML 데이터를 반환하는 메서드에도 유용합니다.

[ScriptMethod (ResponseFormat=ResponseFormat.Xml)] public XmlDocument GetData() { ... }

또는 일반적으로 JSON을 지원하지 않는 형식을 직렬화/역직렬화할 수 있도록 사용자 지정 JSON 변환기를 만들어 등록할 수도 있습니다. ASP.NET AJAX January Futures CTP에는 이러한 변환기가 세 가지(각각 DataSet, DataTable 및 DataRow용) 포함되어 있습니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/04/13 22:38

제목을 어떻게 정해야 될까 상당히 고민이 되는군요...

 

AJAX.NET이 등장하면서 AJAX의 다양한 기능을 손쉽게 사용할 수 있습니다.

 

AJAX.NET에는Server Script뿐 아니라 Client Script도 제공이 되어 다양한 클래스를 이용할 수도 있으며AjaxControlToolkit

 

AJAX기능이 내포된 컨트롤들도 포함하고 있습니다.

 

UpdatePanel에 서버컨트롤을 올려 놓기만 하면 모두 비동기식으로 동작하게 되는데요. 그냥 쉽게 웹페이지의 모든 컨트롤들을

 

UpdatePanel에 올려 놓게 되면 화면이 깜빡이지 않는다는 점 외에 기존의 동기식 방식과 별차이가 없어 보입니다.

 

고로 필요한 부분을 적절하게 파악해서 그 필요한 부분만 UpdatePanel에 올려 놓는 것이 좋다고 생각이 드네요...

 

하지만 이런 경우가 있을 수도 있지요. UpdatePanel 밖의 컨트롤에도 어떠한 데이터를 전달해줘야 한다.

 

즉, UpdatePanel이 업데이트 되면서 어떠한 값을 일반HTML태그에 전달해주는 것이죠.

 

이런 기능을 도와주는 메소드가 있는데요.ScriptManager클래스의 RegiserDataItem메서드입니다.

 

추가 코멘트(2007-04-18)

 

 

ScriptManager클래스의 정적 메서드로 RegisterClientScriptBlock도 있습니다. 이 메서드는 정적 메서드이기 때문에

 

ScriptManager컨트롤의 ID나 현재 페이지의 ScriptManager를 얻어 올 수 있는 ScriptManager.GerCurrent메서드로는 접근이 안됩니다.

 

 

이 메서드와 Page클래스의ClientScript.RegisterStartupScript메서드를 이용한다면 쉽게 기능을 구현할 수가 있습니다.

 

그럼 예제를 보여드리겠습니다. AJAX Enabled 프로젝트를 하나 생성하고

 

<%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="Default.aspx.cs"Inherits="DataItemTest._Default"%>

 

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<htmlxmlns="http://www.w3.org/1999/xhtml">

<headrunat="server">

  <title>Untitled Page</title>

  <scripttype="text/javascript">

       functiongetServerDate(argument)

      {

            document.getElementById("Text1").value = argument;

      }

  </script>

</head>

<body>

  <formid="form1"runat="server">

       <asp:ScriptManagerID="ScriptManager1"runat="server"/>

  <div>

       <asp:UpdatePanelID="UpdatePanel1"runat="server"RenderMode="Inline"UpdateMode="Conditional">

           <ContentTemplate>

               UpdatePanel안의 텍스트박스(서버컨트롤)

              <asp:TextBoxID="TextBox1"runat="server"></asp:TextBox>

           </ContentTemplate>

           <Triggers>

              <asp:AsyncPostBackTriggerControlID="Button1"EventName="Click"/>

           </Triggers>

       </asp:UpdatePanel>

       </div><br/>

       <asp:ButtonID="Button1"runat="server"OnClick="Button1_Click"Text="클릭"/>

       <br/>

        UpdatePanel밖의 텍스트박스(일반컨트롤)

       <inputid="Text1"type="text"/>

  </form>

</body>

</html>

 

위와 같이 aspx페이지를 구성합니다. 버튼컨트롤은 UpdatePanel밖에 위치하지만 UpdatePanel의Triggers에 의해 비동기 호출이 가능합니다.

 

그리고 그 아래는 일반 HTML컨트롤이 존재하며 자바스크립트 함수는 서버로부터 넘겨받은 값을 컨트롤에 넣어주게 됩니다.

 

일단 저 자바스크립트 함수를 버튼이 클릭해서 서버측의 Button_Click이벤트가 일어난 후 작동되게 해야겠지요?

 

그러기 위해서 Page_Load이벤트에 다음과 같은 구문을 넣어줍니다.

 

       protectedvoidPage_Load(objectsender,EventArgse)

        {

           this.ClientScript.RegisterStartupScript(this.GetType(),"PageLoadedEvent","<script type=\"text/javascript\">Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(DefaultPageLoaded);function DefaultPageLoaded(sender, args){var item = args.get_dataItems();getServerDate(item['literal1']);}</script>");

        }

 

add_pageLoading메서드로 이벤트 등록을 해주고 이벤트를 받을 자바스크립트 메서드를 정의해줍니다.

 

DefaultPageLoaded메서드에서 두번째 인자로 받는 것이 서버에서 넣어준 데이터를 담고 있는 객체가 됩니다.

 

그 인자의 get_dataItems 메서드를 호출하여 서버에서 넣어준 데이터를 받아오게 되고 이 데이터를 다시 aspx에서 정의한

 

자바스크립트 메서드에 넘겨주는 것 입니다.

 

이 동작은 AjaxControlToolkit의 Commit메서드와 비슷한 역할을 합니다. AjaxControlToolkit의 각각의 Extender의 속성을 보게 되면

 

CommitScript라는 속성이 있는데요. 이 속성의 값에 들어있는 자바스크립트 메서드나 스크립트 구문이 위의 getServerDate(item['literal1'])

 

정도가 된다고 생각하시면 될듯 하네요. 저도 정확하게 Commit메서드와 CommitScript를 역추적하여 확인하려 했지만 시간관계상 패쑤해써요.

 

아무튼 이제 Button1_Click이벤트에서 서버컨트롤인 TextBox에 값을 넣어주고 그 값을 RegisterDataItem에 넣어줘야겠네요.

 

       protectedvoidButton1_Click(objectsender,EventArgse)

        {

            TextBox1.Text =DateTime.Now.ToString();

           Literalliteral1 =newLiteral();

            literal1.ID ="literal1";

           ScriptManager.GetCurrent(this.Page).RegisterDataItem(literal1,DateTime.Now.ToString());

        }

 

Literal컨트롤은 RegisterDataItem의 첫번째 인자인 컨트롤이 됩니다. 이렇게 구성하면 끝입니다.

 

추가 코멘트에서 말씀드린 것 처럼 RegisterClientScriptBlock메서드는 아래처럼 가능 합니다. 솔직히 이게 더 간단명료하군요.

ScriptManager.RegisterClientScriptBlock(this.Page,this.GetType(),"keyValue","alert('test');",true);

 

마지막 인자의 bool값은 scripte태그를 붙일건지 아닌지를 결정합니다. true로 할 경우 <script>를 사용하면 에러를 발생합니다.

 

약간 어려운듯 하지만 손쉽게 가능하지 않습니까??

 

이런 기능이 뭐가 필요하겠냐고 반문하실 수도 있지만 언젠가는 필요하게 될겁니다. ㅋ 저도 필요로해서 찾아봤고 사용중입니다.

 

이 보다 더 나은 방법이나 간단한 방법이 있을 수도 있지만 제가 저 기능을 생각하게 해준 것이 AjaxControlToolkit의 Commit메서드여서

 

그 메서드에 대해서 알아보다 보니 RegisterDataItem을 알게 된 것 입니다.

 

그럼 마지막으로 위의 페이지를 실행한 화면을 끝으로 마칩니다. 간단하지만 유용하게 사용될 수 있는 팁이 되기를 바랍니다.

 

 

사용자 삽입 이미지

 

 

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/03/26 20:13

UpdateProgress 컨트롤은 UpdatePanel의 내용이 비동기식으로 변경될 경우에 사용자에게 보여지는 내용입니다.


보통 웹사이트를 보면 "페이지가 변경중입니다..."와 같은 비슷한 메세지를 본적이 있을 것 입니다.


UpdatePanel에서 페이지 변경이 이뤄지는데 그 작업이 오래 걸리는 작업이던지 어떤 이유에서 조금 오래 걸리는 작업이라고 할때


사용자는 가만히... 변경이 완료될 때 까지 이 페이지가 변경이 되는 것 인지 아닌지 알 수가 없습니다.


그래서 친절하게 페이지가 변경중이라는 메세지를 보여주고 완료가 되면 이 메세지를 안보이게 해줍니다.


AJAX가 나오기 이전에는 DIV태그등으로 사용자의 클릭이 있으면 DIV의 display속성을 block등으로 사용자에게 나타내고 완료가 되면


display속성을 none으로 하여 사용자에게 안보이기 했습니다.


AJAX에서는 좀 더 쉽게 이를 구현 할 수 있게 하기 위해 UpdateProgress 컨트롤을 지원해줍니다.


UpdateProgress 컨트롤의 초간단 예제를 보시겠습니다.


프로젝트로 AJAX웹 응용프로그램을 하나 생성하고 aspx페이지의 디자인 소스에 아래의 코드를 작성합니다.


       <asp:ScriptManagerID="ScriptManager1"runat="server">

       </asp:ScriptManager>

       <asp:UpdatePanelID="UpdatePanel1"runat="server">

           <ContentTemplate>

              <asp:LabelID="Label1"runat="server"Height="27px"Text="Label"Width="343px"></asp:Label>

              <br/>

              <asp:ButtonID="Button1"runat="server"Text="Button"OnClick="Button1_Click"/>

           </ContentTemplate>

       </asp:UpdatePanel>

       <asp:UpdateProgressID="UpdateProgress1"runat="server"AssociatedUpdatePanelID="UpdatePanel1">

           <ProgressTemplate>             

           <tablealign="center"id="UpdateProgressTable">

                   <tr>

                       <tdalign="center">

                          <asp:ImageID="Image1"runat="server"ImageUrl="~/image/ajax-loader.gif"/>

                       <br/>페이지 변경 중 입니다...

                       <br/>

                       <inputid="Button2"type="button"value="취소"onclick="CancelAsyncPostBack()"/>

                       </td>

                   </tr>

              </table>

              </ProgressTemplate>

       </asp:UpdateProgress>


AssociatedUpdatePanelID속성은 UpdateProgress가 어떤 UpdatePanel이 페이지 변경이 될 때 사용이 되는지 지정해줍니다.


Button1의 OnClick속성에 클릭 이벤트를 하나 주는데요. UpdateProgress의 동작을 잘 볼 수 있게 일부러 작업 시간을 임의적으로 늘립니다.


아래의 코드는 Button1의 클릭 이벤트 코드이며 Label1에 현재 날짜를 출력해주는 코드입니다.


       protectedvoidButton1_Click(objectsender,EventArgse)

        {

            System.Threading.Thread.Sleep(3000);

            Label1.Text ="현재시간은 "+DateTime.Now.ToString() +" 입니다.";

        }


Thread클래스의 Sleep메소드를 호출합니다. 이는 현재 쓰레드를 지정된 시간만큼 대기 합니다. 메소드 인자는 그 시간인데요 단위가


ms입니다. 즉, 3000은 3초가 되는 것 입니다. 이렇게 코드를 구성하여 실행을 해보면...

사용자 삽입 이미지

왼쪽과 같은 화면이 나오게 됩니다. UpdateProgress가 UpdatePanel의 하단에 위치하게 됩니다.


그런데... 저 메세지가 나오는 것은 좋은데 페이지 변경이 이뤄지는 동안 사용자가 아무 작업도


못하게 하고 싶을 수도 있습니다. 혹시 모를 오동작을 위해서 말이지요...


그래서 UpdateProgress를 화면 전체에 나타내려고 합니다. 화면 전체를 덮으려는 것이죠.


또 UpdateProgress에 취소 버튼을 두어 사용자가 언제든지 취소를 할 수 있게 하려 합니다.



먼저 화면 전체를 덮는 부분을 설명드리겠습니다.


이는 웹개발을 해본 개발자라면 쉽게 생각이 날 수도 있습니다. UpdateProgress안의 table태그의 width,height속성을 전체화면 크기로


주고 z-index의 수치를 높게 주면 전체 화면을 덮을 수 있습니다. 저도 그렇게 쉽게 생각하고 코딩에 들어갔습니다.


그러나... 사용자 브라우져 크기를 알기 위해 보통 사용하던... 자바스크립트 코드가 있습니다.


document.body.clientWidth, document.body.clientHeight 이죠....


그런데 이 값들이...이상하게 나오는 것 입니다. width는 제대로 인데 height가 이상한 값이 나옵니다.


궁금하시다면 위의 코드에서 document.body.clientHeight를 확인해보세요.


자세히 살펴본 결과 정말...정확하게 매정하게도.. body태그의 높이를 리턴합니다. 이전에 작성할 때는 아무렇지도 않았는데 말이지요..


왜 그럴까 생각하다가... 혹시 모를 <!DOCTYPE>태그를 지웠습니다. 그랬더니... 제가 원하는대로 잘나옵니다.


범인이 저 DOCTYPE이였습니다. 저 태그를 지우면 되지만 aspx를 Visual Studio에서 생성하면 자동으로 생기게 됩니다.


그리고.. 이는 버그도 아니고 오히려 웹 개발시 지켜야 할 표준이죠. 그리고 DOCTYPE의 속성을 보면 aspx페이지가 XHTML 1.0기준입니다.


그러니 document.body.clientHeight가 아닌 다른 방법으로 사용자 브라우져 크기를 알아야 합니다.


열심히 찾았지만 쉽게 답이 나오지 않았습니다. window.screen은 사용자 컴퓨터의 해상도 이므로 원하는 값이 아닙니다.


그러던 중 document.documentElement.clientHeight를 발견했습니다. 바로 테스트에 들어갔지만 이 값은 "0"이 나옵니다.


documentElement가 HTML태그인데...왜 이 값은 "0"이 나오는지 당췌 이해할 수가 없었습니다.


그래서...예전 태오님 세미나에 봤던 AJAX Control Toolkit에 ModalPopupExtender가 생각이 났습니다.


그래서 예제를 실행해보니 이 Extender는 정확하게 잘 동작했습니다. 이상하게 생각한 저는 ModalPopupExtender코드를 분석했습니다.


저 Extender의 자바스크립트 코드에서 height를 알아내는 코드가 있었습니다. 그 코드는...


       varclientBounds = CommonToolkitScripts.getClientBounds();

       varclientWidth = clientBounds.width;

       varclientHeight = clientBounds.height;


입니다. CommonToolkitScript클래스의 getClientBounds메서드입니다. 그 메서드가 어떤 객체를 리턴해주는 모양입니다.


그 객체에는 width와 height라는 속성이 있나 봅니다. 그래서 해당 메서드를 또 찾아보기로 했습니다.


CommonToolkitScript라는 이름에서 풍기는 이미지...느껴지시나요?? 뭔가...공통 모듈같은 뭐 그런 이미지...


그래서 AJAX Control Toolkit의 설치 폴더로 향하니... ExtenderBase와 Common폴더가 있습니다. 이름에서도 알 수 있듯이 Base랍니다. ㅋ


Base폴더에는 자바스크립트 파일은 딸랑 하나 있습니다. 반가운 일이죠...하나만 분석하면 되니까요....


그러나 실망스럽게도 ExtenderBase폴더는 아니였습니다. 그래서 Common폴더로 가니 4개의 파일이 있는데 이중 Common.js를


열어보기로 하고 스크롤 했습니다. 그랬더니...반갑게도 getClientBounds메서드가 절 반겨주었습니다.


Common.js의 getClientBounds의 내용을 보여드리면...


   getClientBounds :function() {

       /// <summary>

       /// Gets the width and height of the browser client window (excluding scrollbars)

       /// </summary>

       /// <returns type="Sys.UI.Bounds">

       /// Browser's client width and height

       /// </returns>


       varclientWidth;

       varclientHeight;

       switch(Sys.Browser.agent) {

           caseSys.Browser.InternetExplorer:

               clientWidth = document.documentElement.clientWidth;

               clientHeight = document.documentElement.clientHeight;

              break;

           caseSys.Browser.Safari:

               clientWidth = window.innerWidth;

               clientHeight = window.innerHeight;

              break;

           caseSys.Browser.Opera:

               clientWidth = Math.min(window.innerWidth, document.body.clientWidth);

               clientHeight = Math.min(window.innerHeight, document.body.clientHeight);

              break;

           default: // Sys.Browser.Firefox, etc.

               clientWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);

               clientHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);

              break;

        }

       returnnewSys.UI.Bounds(0, 0, clientWidth, clientHeight);

   },



이렇습니다. Sys.Browser.InternetExplorer... Sys.Browser클래스는 AJAX의 Client Script입니다. 이 레퍼런스는여기서 볼 수 있습니다.


어라?? 여기서도 document.documentElement.clientHeight로 알아 냅니다. 그리고 Sys.UI.Bounds클래스를 생성하여 리턴합니다.


그런데 분면 저도 저 코드를 실행해 봤지만 그 값이 0이였습니다. 헉;;; DOCTYPE태그를 빼고 테스트를 했습니다.


DOCTYPE태그가 없으면 doucment.documentElement.clientHeight의 값은 0입니다.


된장할... 아무튼 이제 저 코드를 추가하여 구현 해보겠습니다. DOCTYPE태그는 없으면 안된다는거~


그리고... 취소버튼을 눌렀을 경우도 구현 해보겠습니다. 이는 Sys.WebForms.PageRequestManager클래스의 getInstance메서드를


호출하고 리턴되는 객체의 abortPostBack() 메서드를 호출하는 것 입니다.


UpdateProgress의 스타일까지 포함한 전체 소스입니다.


<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<htmlxmlns="http://www.w3.org/1999/xhtml">

<headrunat="server">

  <title>제목 없음</title>

  <styletype="text/css">

           #UpdateProgressTable{

          position:absolute;

          z-index:100;

          top:0px;

          margin:0px;

          left:0px;

          background-color:#FAFAFA;

          border-width:0px;

          border-style:None;

          font-family:"돋움";

          filter:progid:DXImageTransform.Microsoft.Shadow(color=#ffffff, Direction=0, Strength=0)alpha(Opacity=60);

        }

  </style>

  <scripttype="text/javascript">

  functionUpdateProgressInit()

   {

       varprogress = $get("UpdateProgressTable");

       if(typeof(progress) =="object")

        {

            progress.style.width = getClientBounds().width;

            progress.style.height = getClientBounds().height;

        }

   }

  functionCancelAsyncPostBack()

   {

       varprm = Sys.WebForms.PageRequestManager.getInstance();

       if(prm.get_isInAsyncPostBack())

        {

            prm.abortPostBack();

        }

   }

  functiongetClientBounds()

   {

       varclientWidth;

       varclientHeight;

       switch(Sys.Browser.agent) {

       caseSys.Browser.InternetExplorer:

            clientWidth = document.documentElement.clientWidth;

            clientHeight = document.documentElement.clientHeight;

           break;

       caseSys.Browser.Safari:

            clientWidth = window.innerWidth;

            clientHeight = window.innerHeight;

           break;

       caseSys.Browser.Opera:

            clientWidth = Math.min(window.innerWidth, document.body.clientWidth);

            clientHeight = Math.min(window.innerHeight, document.body.clientHeight);

           break;

       default: // Sys.Browser.Firefox, etc.

            clientWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);

            clientHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);

           break;

      }

       returnnewSys.UI.Bounds(0, 0, clientWidth, clientHeight);

   }

  </script>

</head>

<body>

  <formid="form1"runat="server">

       <asp:ScriptManagerID="ScriptManager1"runat="server">

       </asp:ScriptManager>

       <asp:UpdatePanelID="UpdatePanel1"runat="server">

           <ContentTemplate>

              <asp:LabelID="Label1"runat="server"Height="27px"Text="Label"Width="343px"></asp:Label>

              <br/>

              <asp:ButtonID="Button1"runat="server"Text="Button"OnClick="Button1_Click"/>

           </ContentTemplate>

       </asp:UpdatePanel>

       <asp:UpdateProgressID="UpdateProgress1"runat="server"AssociatedUpdatePanelID="UpdatePanel1">

           <ProgressTemplate>             

           <tablealign="left"id="UpdateProgressTable">

                   <tr>

                       <tdalign="center">

                          <asp:ImageID="Image1"runat="server"ImageUrl="~/image/ajax-loader.gif"/>

                       <br/>페이지 변경 중 입니다...

                       <br/>

                       <inputid="Button2"type="button"value="취소"onclick="CancelAsyncPostBack()"/>

                       </td>

                   </tr>

              </table>

              </ProgressTemplate>

       </asp:UpdateProgress>

     <scripttype="text/javascript">

           UpdateProgressInit();

     </script>

  </form>

</body>

</html>


위의 코드로 작성하고 실행을 시켜보세요. 약간의 오차때문에 저는 스크롤바가 생기긴 했지만 화면 전체를 덮었습니다.


그리고 사용자가 브라우져를 리사이징 했을 경우는 제대로 동작하지 않습니다. 그 이유는 처음 로드시 크기를 알아내 UpdateProgress의


크기를 지정하니까요... 이를 위해서는 resize이벤트를 잡아내서 재 정의해주는 추가 작업도 필요합니다.


또한 위 방법은 IE7이상 버전에서는 좋기는 하지만 그 이하버전에서는 SELECT태그는 덮지 못합니다. 이것은 여러가지 꽁수로 해결해야 합니다.


왜 그렇게 되는지 그 이유와 해결 방법에 대해서는안재우님의 블로그에 방문해보세요.


마지막으로 만약에 DOCTYPE이 있을 수도 있고 없을 수도 있다. 이럴 경우에는 어떻게 해야 하는가에 대해 설명하겠습니다.


ControlToolkit의 Extender를 가지고 테스트를 해보면 알겠지만 Extender들은 DOCTYPE이 있거나 없어도 잘 동작한다.


그 이유는 document.documentElement.clientHeight와 document.body.clientHeight중 큰것을 사용하기 때문인데 이 코드는..


  functionUpdateProgressInit()

   {

       varprogress = $get("UpdateProgressTable");

       if(typeof(progress) =="object")

        {

            progress.style.width = Math.max(getClientBounds().width,document.body.clientWidth);

            progress.style.height = Math.max(getClientBounds().height,document.body.clientHeight);

        }

   }


이렇게 사용하면 됩니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/03/23 23:40

예전부터 느꼈으면 좋았을 웹 표준에 대한 관심이 높아만 진다. 솔직히 기존에 만들었던 것을 보면 웹 표준을 지킨 것이 없을 정도이다.

 

비스타가 나오면서 ActiveX에 대한 뜨거운? 비난이 쏟아지면서 웹 표준의 비중을 더욱더 높여준 계기가 되었다.

 

ASP.NET 2.0으로 웹페이지를 만들다 보면 웹표준을 따르지만 주로 IE에서 돌아가는 웹페이지를 만들던 개발자나 디자이너들은

 

표준을 잘 지키지 않는 편이다. 예를 들자면 테이블 태그의 남용이나 JavaScript의 문법이 IE에서만 동작하는 등의 코드들...

 

간혹 이전 코드들을 참고해서 개발하다 보면 자바스크립트가 제대로 동작하지 않는다. 흔한 일은 아니지만 이런 문제로 추적의 추적을 통해

 

찾기는 하지만...ㅠ

 

MSDN에 기사에 웹 표준을 이용한 웹사이트 구축이란 기사가 있다. 분량이 많다... 웹 간행물? 치곤...ㅠ

 

게다가 영어다. OTL 간단한 분량이라면 어느 정도 읽어 보겠지만.. 저 분량을 그것도 영어로 된 글을 어떻게 다 볼까?? ㅠ

 

아무튼... 해당 기사는Building ASP.NET 2.0 Web Sites Using Web Standards

 

아래와 같은 내용들이 기사에 포함되어 있다.

 

Introduction
Building XHTML Web Sites
Versions of the XHTML Standard
Creating XHTML Pages
XHTML and ASP.NET Controls
Validating XHTML Pages
XHTML and DOCTYPE Switching
XHTML and MIME Types
Configuring XHTML Conformance
Accessibility Standards
Accessibility Improvements in ASP.NET 2.0
Creating Accessible Images
Creating Accessible Forms
Creating Accessible Navigation
Creating Accessible Data
Creating Accessible XHTML
Creating Accessible Scripts
Validating Pages for Accessibility
Accessing the Amazon Web Services
The Default Page
XHTML Features of the Default Page
Accessibility Features of the Default Page
The Search Page
XHTML Features of the Search Page
Accessibility Features of the Search Page
The Master Page
XHTML Features of the Master Page
Accessibility Features of the Master Page

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari