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/28 00:34

이전 AJAX.NET Professional 포스트에서는 기본적인 사용 방법에 대해서 설명해드렸는데 이번에는 조금 수준 높은?? 방법에 대해 설명드릴까 합니다.

버튼을 클릭하면 데이터베이스에서 데이터를 받아 오고 이 데이터를 HTML의 Table태그에 출력하는 방식입니다.

물론 이것을 실무에서 사용하기엔 많이 부족하지만 간단한 예제를 보여드리고자 함이니 참고하시면 좋을 것 같습니다.


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

    2 

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

    4 

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

    6 <headrunat="server">

    7   <title>제목 없음</title>

    8   <scripttype="text/javascript">

    9      functionErrorCheck(args)

   10       {

   11            if(args.error !=null)

   12             {

   13                alert(args.error);

   14               returnfalse;

   15             }

   16            returntrue;

   17       }

   18      //버튼 클릭시 호출

   19      functiongetData()

   20       {

   21            //cs에서 정의한  Ajax메서드 호출

   22            //네임스페이스명.클래스명.메서드명(콜백함수)

   23             AjaxProTableExam._Default.getData(titlesBinding);

   24       }

   25      //응답 데이터를 전달받는 콜백함수

   26      functiontitlesBinding(args)

   27       {

   28            if(!ErrorCheck(args))

   29               returnfalse;

   30             alert(args.value.Tables[0].Rows.length +"행을 Table태그에 출력합니다.");

   31            varDataTable = args.value.Tables[0];

   32            varDataRowLength = DataTable.Rows.length;

   33            varDataColumnLength = DataTable.Columns.length;

   34            if(DataRowLength == 0)//데이터가 없을 경우

   35             {

   36                EmptyDataDisplay(DataColumnLength);

   37               returnfalse;

   38             }

   39            varcurrentRow;

   40            for(varrowsLength = 0; rowsLength < DataRowLength; rowsLength++)

   41             {

   42                currentRow = CreateRow(document.getElementById("titles"));

   43               for(varcellsLength = 0; cellsLength < DataColumnLength; cellsLength++)

   44                     CreateCells(currentRow, cellsLength, DataTable.Rows[rowsLength][DataTable.Columns[cellsLength].Name]);

   45             }

   46       }

   47      functionEmptyDataDisplay(columnLength)

   48       {

   49            varcells = CreateRow(document.getElementById("titles")).insertCell(0);

   50             cells.style.height ="20px";

   51             cells.appendChild(document.createTextNode("데이터가 존재하지 않습니다."));

   52             cells.colSpan = columnLength;

   53       }

   54      functionCreateRow(tableElement)

   55       {

   56            returntableElement.insertRow(tableElement.childNodes[0].childNodes.length);

   57       }

   58      functionCreateCells(trElement, cellIndex, value)

   59       {

   60            varcells = trElement.insertCell(cellIndex);

   61             cells.style.height ="20px";

   62             cells.appendChild(document.createTextNode(value));

   63       }

   64   </script>

   65 </head>

   66 <body>

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

   68   <div>

   69        <asp:ButtonID="Button1"runat="server"Text="클릭하세요."UseSubmitBehavior="False"OnClientClick="getData(); return false;"/>

   70        <tableid="titles"cellpadding="5"cellspacing="1"border="1">

   71            <tr>

   72               <tdstyle="background-color:Gray;color:White;">title_id</td>

   73               <tdstyle="background-color:Gray;color:White;">title</td>

   74            </tr>

   75         </table> 

   76   </div>

   77   </form>

   78 </body>

   79 </html>


자바스크립트 부분을 설명해 드리면 버튼을 클릭할 경우 서버측의 Ajax메서드를 호출하고 DataSet 타입의 데이터 집합을 받아 옵니다.

그리고 콜백함수에서는 행과 열의 수에 따라 지정한 Table태그의 자식 element인 TR/TD element를 만들어 내는 코드입니다.

문자열에 태그를 넣어 innerHTML로 만들지 않고 나름 표준적인? 방식으로 사용했습니다.

받아온 Row의 갯수가 0일 경우 "데이터가 존재하지 않습니다."라는 문자를 출력하고 위의 코드가 다소 미운 UI가 나옵니다. style은 다양하게 적용할 수 있으나 소스가 길어지는 관계상(사실은...귀차니즘;;ㅠ) 생략하였습니다.


자바스크립트 코드중 궁금한 것은 댓글달아 주시구요.

코드가 조금 엉성하거나 좋아 보이지 않는다면 그건...제 내공 부족으로 인해 알흠답게 코딩을 못하기 때문에...ㅠ


cs코드는 아래와 같습니다.


usingSystem;

usingSystem.Data;

usingSystem.Configuration;

usingSystem.Collections;

usingSystem.Web;

usingSystem.Web.Security;

usingSystem.Web.UI;

usingSystem.Web.UI.WebControls;

usingSystem.Web.UI.WebControls.WebParts;

usingSystem.Web.UI.HtmlControls;

usingSystem.Data.SqlClient;

namespaceAjaxProTableExam

{

  publicpartialclass_Default: System.Web.UI.Page

   {

       protectedvoidPage_Load(objectsender,EventArgse)

        {

            AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));

        }

        [AjaxPro.AjaxMethod]

       publicDataSetgetData()

        {

           using(SqlConnectioncon =newSqlConnection("server=(local);database=pubs;user id=sa;password=****;"))

            {

              SqlCommandcmd =newSqlCommand("select title_id, title from titles order by title_id", con);

               con.Open();

              DataSetds =newDataSet();

              SqlDataAdapterda =newSqlDataAdapter(cmd);

               da.Fill(ds);

               con.Close();

              returnds;

            }

        }

   }

}



 

사용자 삽입 이미지
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2007/06/15 20:10

ASP.NET에서 AJAX를 이용하여 좀 더 편하게 웹사이트를 개발하기 위해서ASP.NET AJAX1.0이란 라이브러리를 제공합니다.

저 라이브러리는 ASP.NET 2.0에서 지원이 되기때문에 ASP.NET 1.X버전은 사용할 수가 없었습니다.

ASP.NET 1.X시절 AJAX를 좀 더 편리하게 사용하여 개발할 수 있게 도와준 라이브러리가 있었습니다.

AJAX.NET이란 이름으로 MSDN에도 소개가 되었었죠...

Michael Schwarz라는 개발자가 개인적으로 만든 라이브러리인데 간단하게 사용할 수 있어서 저도 1.X시절에 이를 이용하여 개발을 했었습니다. 잠깐 잊고 있었는데 우연하게 다시금 찾게 되어 웹사이트에 들어가 보니 떡하니... 2.0도 지원하는 라이브러리를 내놨네요...

AJAX.NET Professional이란 이름인데요.이 웹사이트는 여기, 라이브러리 개발자인Michael Schwarz의 개인 블로그는 여기로 방문하면 됩니다. 좀 더 많은 기능을 제공하는 것 같기는 한데 영어 실력도 형편없고 머리도 아프고 이런저런 핑계를 다 대고는 싶지만...ㅠ

그리하여..... 1.X시절에MSDN에 소개가 되었고태오사이트에서도 소개가 됐던 예제를 2.0버전을 다운 받아서 비슷한 예제를 소개할까 합니다.


AJAX.NET Professional다운로드참고로 6.대 버전으로 다운로드 하세요. 7.대 버전은 제 예제가 실행이 안되더군요. DataSet을 리턴받지 못하는거 같던데 이유는 찾기 귀찮습니다.

다운받은 dll파일을 참조추가로 추가해주면 라이브러리를 이용할 준비는 끝입니다.

그럼 예제 나갑니다. pubs 데이터베이스의 titles테이블에서 type을 선택하면 type에 해당하는 title들을 반환하는 예제입니다.

일단 예제를 보고 간단하게 설명하렵니다.


web.config의 system.web하위에 아래의 코드를 추가하세요.

        <httpHandlers>

            <addverb="*"path="*.ashx"type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>

        </httpHandlers>



aspx소스....


<%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="Default.aspx.cs"
Inherits="AjaxNetProExam._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>AJAX.NET Professional Example</title>

  <scripttype="text/javascript">

     functiongetTitle(obj)

      {

           var_value = obj.options[obj.selectedIndex].value;

           if(_value !="")

            {

               AjaxNetProExam._Default.GetTitle(_value, _callBack1);

            }

      }

     function_callBack1(argument)

      {

           if(argument.error !=null)

               alert(argument.error.Message);

           else

            {

              varDropDownList2 = document.getElementById("DropDownList2");

               DropDownList2.options.length = 0;

              for(i=0;i<argument.value.Tables[0].Rows.length;i++)

               {

                    DropDownList2.options[DropDownList2.options.length] =newOption(argument.value.Tables[0].Rows[i].title,argument.value.Tables[0].Rows[i].title);

               }

            }

      }

     function_callBack2(argument)

      {

            alert(argument.value);

      }

  </script>

</head>

<body>

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

  <div>

       <asp:DropDownListID="DropDownList1"runat="server"onchange="getTitle(this);">

           <asp:ListItemText="전체"Value=""/>

           <asp:ListItemText="business"Value="business"/>

           <asp:ListItemText="mod_cook"Value="mod_cook"/>

           <asp:ListItemText="popular_comp"Value="popular_comp"/>

           <asp:ListItemText="psychology"Value="psychology"/>

           <asp:ListItemText="trad_cook"Value="trad_cook"/>

           <asp:ListItemText="UNDECIDED"Value="UNDECIDED"/>

       </asp:DropDownList>

       <asp:DropDownListID="DropDownList2"runat="server">

       </asp:DropDownList>

       <inputtype="button"value="XML보기"onclick="AjaxNetProExam._Default.GetDataSet(_callBack2);"/>

  </div>

  </form>

</body>

</html>


aspx.cs소스....


usingSystem;

usingSystem.Data;

usingSystem.Configuration;

usingSystem.Collections;

usingSystem.Web;

usingSystem.Web.Security;

usingSystem.Web.UI;

usingSystem.Web.UI.WebControls;

usingSystem.Web.UI.WebControls.WebParts;

usingSystem.Web.UI.HtmlControls;

usingSystem.Data.SqlClient;


namespaceAjaxNetProExam

{

  publicpartialclass_Default: System.Web.UI.Page

   {

       privatestaticDataSetds;

       protectedvoidPage_Load(objectsender,EventArgse)

        {

            AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));

        }


        [AjaxPro.AjaxMethod]

       publicDataSetGetTitle(stringtype)

        {

           using(SqlConnectioncon =newSqlConnection("server=(local);database=pubs;user id=sa;password=*****"))

            {

              SqlCommandcmd =newSqlCommand();

               cmd.Connection = con;

               cmd.CommandText ="select title from titles where type = @paramType group by title order by title";

               cmd.Parameters.Add("@paramType",SqlDbType.VarChar);

               cmd.Parameters["@paramType"].Value = type;

               con.Open();

               ds =newDataSet();

              SqlDataAdapterda =newSqlDataAdapter(cmd);

               da.Fill(ds);

              returnds;

            }

        }


        [AjaxPro.AjaxMethod]

       publicstringGetDataSet()

        {

           returnds.GetXml();

        }

   }

}


AJAX.NET Pro를 사용하기 위해선 반드시 위에서 말한 web.config에 코드를 추가하고 AJAX에 사용될 메서드가 있는 클래스에 아래의 코드가 존재해야 합니다.

AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));


그리고 AJAX메서드는 [AjaxPro.AjaxMethod]를 위에 추가해주면 끝입니다. 이 코드 추가로 JavaScript에서 cs의 함수를 호출할 수 있는

즉, AJAX를 이용한 개발이 완료가 된 것 입니다.

자바스크립트에서 cs의 AJAX메서드의 호출은

AJAX메서드가 포함된 클래스의 네임스페이스.클래스.AJAX메서드명으로 호출을 합니다.

그런 방법으로 나온 코드가

AjaxNetProExam._Default.GetTitle(_value, _callBack1);


호출할 때 괄호안에 필수 인자가 있는데요. 그 인자는 결과를 리턴 받을 자바스크립트 메서드이고 그 메서드는 하나의 인자를 받습니다.

그 인자에 리턴 받은 결과가 담기게 되지요.

그리고 AJAX메서드에 인자가 있다면 그 인자를 차례대로 자바스크립트에서도 넣어주면 됩니다.

단, 맨 마지막은 리턴 받을 자바스크립트 메서드여야 합니다.

예제에서는 사용자가 선택한 DropDownList의 값입니다. 이 값을 선택하면 AJAX메서드를 호출하여 title테이블의 type에 해당하는

title정보를 DataSet에 담고 그 DataSet을 리턴하게 됩니다.


인자의 value속성에 결과 값이 들어오게 되는데 이 결과값에는 우리가 C#에서 DataSet을 다루는 문법과 비슷합니다.

Tables[0].Rows[0].title

비슷하지 않나요?? 마지막 title은 컬럼명입니다. 자바스크립트 코드를 보시면 이해가 될 것으로 생각이 되구요.

위 예제를 비록 1.X버전이긴 하지만 아주~ 잘 설명해주신태오님 강좌를 참고해보세요.

예제가 틀린데요? 라고 한다면 무자게 곤란합니다. 알아서 이해를 하셔요...


한가지 아쉬운 점이 도움말이 없다는거 어디에 있는지 알려주세요.

DataSet으로 리턴 받으면 어떻게 그걸 참조하는지 각 리턴 타입별로 알려주면 안되나... ㅡㅡ;;


예제의 버튼은 해당 DataSet이 어떻게 나오는지 보여주는 버튼입니다.

기타 궁금한 사항은 댓글이나태오사이트에 질문해주세요. 태오님을 포함한 여러 MVP분들이 친절하게 답변해주실 겁니다.

크리에이티브 커먼즈 라이선스
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