티스토리 뷰

출처 : http://blog.naver.com/dotnethelper/60103536438

작성 : 김수영(Microsoft Visual C# MVP)

        .NET N'Gene(http://www.dotnetngene.kr)

        훈스닷넷 SYSOP(http://www.hoons.kr)

버전 : 1.0

   

IT 기술의 변화 및 신 기술의 등장 주기는 과거에 비하여 비교 하지 못할 정도로 빨라 지고 있다. 
정적인 컨텐츠를 단순히 구독하는 입장의 Web 1.0에서 사용자들이 적극적으로 컨텐츠 제작에 참여하는 Web 2.0 지원을 위한 Silverlight, Flex, AJAX등 다양한 RIA(Rich Internet Application) 기술들이 등장하였다. 특히 AJAX(Asynchronous JavaScript and XML) 경우 기존의 웹 기술들을 이용하여 사용자 편의성을 극대화 할 수 있어 현재는 많은 웹 프로젝트에서 보편적으로 사용되어 지고 있다.

   

AJAX는 약어의 의미에서도 알 수 있듯이

  • 서버와의 비동기 통신을 위한 XMLHttpRequest,
  • 데이터 교환 포맷인 XML
  • 프리젠테이션 처리를 위한 XHTML, CSS
  • 로직 처리를 위한 Javascript

를 이용하고 있다.


일반 사용자에게는 웹에서 작업을 쉽게 할 수 있도록 도와 주지만, 그것을 개발하는 개발자에게는 이전보다 더 많은 개발 공수가 들어가야 하는 부담이 되고 있다.
그러므로, Ajax 개발을 좀더 쉽게 할 수 있는 다양한 Framework들이 나오고 있으며 ASP.NET 또한 ASP.NET AJAX를 통하여 지원되어 지고 있다.

    

ASP.NET AJAX에서는 서버컨트롤에 UpdatePanel로 감싸 주기만 하면 개발자가 작성해야 할 많은 부분을 Framework 레벨에서 처리하여 주기 때문에 너무나도 쉽게 사용 가능하다.

UpdatePanel로 작업을 하면 서버에서는 컨트롤 접근은 물론 클라이언트에서 변경된 데이터도 가져와 변경작업을 할 수 있다.

   

[UpdatePanel  선언]

 

<asp:UpdatePanel ID="UpdatePanel1" runat="server">

<ContentTemplate>

<asp:TextBox ID="TextBox1" runat="server" Width="416px"></asp:TextBox>

<asp:Button ID="btnUpdatePanelCall" runat="server" Text="UpdatePanel에서 호출"

onclick="btnUpdatePanelCall_Click" />

</ContentTemplate>

</asp:UpdatePanel>

 
   

하지만, 획기적인 개발 생산성을 자랑하는 UpdatePanel도 단점이 있으니, 그것은 바로 ViewState가 서버 통신에 포함되어 적지 않은 트래픽을 유발하게 되는 것이다. 페이지의 일부분만 변경하기 위해 너무 많은 비용을 발생시키는 것이다.  ASP.NET은 UpdatePanel과 다르게 서버 메소드를 비동기로 사용할 수 있은 PageMethods 도 지원한다.

   

아래 그림에서 왼쪽은 Request 스트림을 오른쪽은 Response 스트림을 보여주고 있다. UpdatePanel 사용시에 ViewState가 같이 전송되는 것을 볼 수 있다. 지금은 크기가 얼마 되지 않지만 ViewState 크기가 클 경우는 성능에 영향을 미치게 되는 것이다. 반면 PageMethods 에서 발생되는 트래픽은 적은 것을 확인 가능하다.

   

지금 얘기하고자 하는 것은 UpdatePanel이 무조건 나쁘다는 것이 아니다. UpdatePanel은 나름의 장점을 가지고 있으며 높은 수준의 추상화가 이루어져 있기 때문에 사용이 쉽고, 특히 개발 생산성 측면에서는 큰 이점을 가지고 온다. 상황에 맞는 적절한 기술을 사용하면 되는 것이다.

   

[UpdatePanel 사용 하였을 경우 스트림]

   

[PageMethods 사용 하였을 경우 스트림]

   

그럼 본격적으로 PageMethods, JSON 등을 사용하여 다이나막한 페이지 개발에 대해 알아 보도록 하자.

   

1. PageMethods 사용 설정

PageMethods를 사용하려면 먼저 ScriptManager에서 PageMethods 사용을 활성화 해주어야 한다.

 

<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true"

runat="server">

</asp:ScriptManager>

 
   

 

2. PageMethods 정의

ScriptManager 설정이 완료 되었으면, 비하인드코드에서 클라이언트에서 호출하기 위한 메소드에 [WebMethod]  어트리뷰트만 설정해 주면 된다.

   

한가지 주의 할 점은 반듯이 static 메소드로 정의 되어야 한다는 것이다. 즉, 메소드 내에서 컨트롤을 참조 할 수 없다.  그러므로, 정의된 PageMethods에서는 컨트롤에 어떤 변경을 처리하는 로직이 아니라 비즈니스 처리만 이루어 져야 한다.  컨트롤 처리는 서버처리의 콜백 이후 클라이언트 스크립트로 처리하여야 한다.


[클라이언트에서 호출 가능한 PageMethods 정의] 

 

[WebMethod]

public static string ServerResult()

{

var resultValue

new BoardProcessResult

{

Completed = true,

Message = String.Format("PageMethods : {0}"DateTime.Now)

};

 

string jsonValue = JsonHelper.Serialize<BoardProcessResult>(resultValue);

 

return jsonValue;

}

 
   

 

3. 클라이언트에서 페이지 메소스 호출

클라이언트 자바스크립트로 호출 형식은 다음과 같다.

 

PageMethods.서버메소드명(서버파라미터들, OnSucceeded콜백, OnFailed콜백)

 

서버 메소드명의 파라미터 목록은 첫 파라미터부터 서버에 정의된 순서대로 나열하면 되며(없으면 생략가능), 마지막으로 성공 했을 때와 실패 했을 경우의 콜백 함수를 정의해 주면 된다.

   

다음 코드에서는 성공했을 때의 콜백 함수를 C#의 익명메소드(Anonymous Method) 와 비슷한 형식으로 표현해 보았다. 성공적으로 서버에서 처리된 데이터를 JSON 형식으로 받은 후 컨트롤 등 부가 적인 처리가 가능하다.

   

[클라이언트에서 PageMethods 호출]

 

<script type="text/javascript">

function severCallJs()

{

PageMethods.ServerResult(function (result)

{

//var resultObj = eval('(' + result + ')');

var resultObj = JSON.parse(result);

 

if (resultObj.Completed)

{

$('input#<%=TextBox1.ClientID %>').val(resultObj.Message);

}

else

{

alert("false : " + resultObj.Message);

}

}

, onFailed);

}

 

function onFailed(error, userContext, methodName)

{

alert(error.get_message());

}

</script>

 
   

 

4. JSON(JavaScript Object Notation) Serialize

XML(eXtensible Markup Language)은 사용자가 쉽게 데이터 구조를 정의하여 사용할 수 있는 텍스트 기반의 특징으로 여러 이기종 시스템과의 상호 운영성 확보를 위하여 많이 사용되어 진다. 
많은 장점을 가진 XML이지만 항상 Element는 시작과 끝 태그가 존재하는 등 XML 자체 특징으로 인하여 데이터가 많아질수록 전체 데이터 사이즈는 점점 커지게 진다.

   

아래 표를 보면 좀더 확실히 차이점을 확인 할 수 있다.

   

[XML/JSON 비교]

   
 

XML

JSON

<BoardResult>
    <Completed>true</Completed>
    <Message>처리완료</Message>
</BoardResult>

{"Completed :true, "Message":"처리완료"}

 
   

 

이러한 이유로 구조화된 데이터 표현의 장점을 살리면서 경량화된 데이터 사이즈를 가질 수 있는 JSON 형식이 나오게 되었다. 현재 JSON은 웹 기반 어플리케이션 개발에서 데이터 교환을 위한 형식으로 많은 주목을 받고 있다.

   

JSON 형식을 사용하기 위해서는 다음과 같은 절차가 필요하다.

   

4.1. 닷넷 사용자 정의 객체의 직렬화(Serialize)

서버에서 정의된 클래스를 JSON 형태로 직렬화 해야 한다. 직접 구현한 모듈을 사용하여도 되지만 FCL(Framework Class Library)에서 이미 지원해 주고 있다.

   
 

에셈블리

System.ServiceModel.Web(System.ServiceModel.Web.dll)

네임스페이스

System.Runtime.Serialization.Json

클래스

DataContractJsonSerializer

 
   

 

사용자 정의 닷넷 객체를 JSON 형식으로 직렬화(Serialize) 하고, JSON 형식를 다시 역직렬화(Deserialize)하는 메소드가 필요하게 된다.  아래 코드는 위 두 가지 기능을 하는 메소드를 정의한 것이다. 특히 다양한 형식을 사용할 수 있도록 제네릭(Generic) 형식을 사용하였다.

JSON 직렬화에 관해서는 다음 블로그를 통해서 좀더 상세한 정보를 볼 수 있다. (.NET 3.5: JSON Serialization using the DataContractJsonSerializer)

   

[JSON 타입으로 직렬화]

 

public static string Serialize<T>(T obj)

{

string json = null;

 

using (MemoryStream ms = new MemoryStream())

{

DataContractJsonSerializer serializer

            = new DataContractJsonSerializer(obj.GetType());

 

serializer.WriteObject(ms, obj);

json = Encoding.UTF8.GetString(ms.ToArray());

}

 

return json;

}

 
   

 

[JSON 타입의 역직렬화]

 

public static T Deserialize<T>(string json)

{

T obj = Activator.CreateInstance<T>();

 

using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))

{

DataContractJsonSerializer serializer

            = new DataContractJsonSerializer(obj.GetType());

 

obj = (T)serializer.ReadObject(ms);

}

 

return obj;

}

 
   

 

직렬화 관련 기능이 정의 되었으면 직렬화할 객체를 정의해 보자. 언뜻 생각해 보면 직렬화 하면 먼저 떠오르는 것이 XML 직렬화 이다. 그리고 XML 직렬화시 클래스에 [Serializable] 어트리뷰트(Attribute)를 선언해 주기만 하면 직렬화 객체로 사용 가능하였다.

   

클래스를 정의해 보자.

   

[직렬화에 사용할 클래스 정의([Serializable]어트리뷰트 사용)]

 

[Serializable]

public sealed class BoardProcessResult

{

public bool Completed { getset; }

public string Message { getset; }

}

 
   

 

이제 직렬화를 수행하면 된다.

 

[WebMethod]

public static string ServerResult()

{

var resultValue

new BoardProcessResult

{

Completed = true,

Message = String.Format("PageMethods : {0}"DateTime.Now)

};

 

string jsonValue = JsonHelper.Serialize<BoardProcessResult>(resultValue);

 

return jsonValue;

}

 
   

 

디버깅 모드에서 jsonValue를 살펴 보면 직렬화된 문자열이 JSON 형식이 아닌 이상한 형태를 띠고 있다.(-.-)

   

[ Serializable 어트리뷰트 선언이 직렬화된 문자열]

   

 

그림에서 보는 것처럼 올바른 JSON 문자열이 아니다.  이유는 클래스에 [Serializable]로 선언 되었기 때문이다.

   

그럼 왜 [Serializable] 를 사용하면 되지 않을까?

우리가 직렬화를 위해 사용한 DataContractJsonSerializer 클래스를 보자. DataContract 이다.

어디서 많이 보지 않았는가? 바로 WCF(Windows Communication Foundation)에서 보았을 것이다.

   

WCF는 크게 ABC 3가지의 중요한 구성요소를 가지고 있다.

   
 

Address

서비스를 사용할 주소(URL, URI 등)

Binding

서비스 전송 프로토콜(tcp, http 등)

Contract

서비스를 위한 계약 조건
(ServiceContract, DataContract)

 
   

 

바로 여기 Contract의 [DataContract]를 위한 클래스인 것이다.

   

그럼 코드를 변경해서 다시 실행하여 보자.  [DataContract] 는 다음 네임스페이스를 먼저 참조 해야 한다.

   
 

에셈블리

System.Runtime.Serialization(System.Runtime.Serialization.dll)

네임스페이스

System.Runtime.Serialization

클래스

DataContractAttribute

 
   

 

[직렬화에 사용할 클래스 정의([DataContract] 어트리뷰트 사용)

 

[DataContract]

public sealed class BoardProcessResult

{

[DataMember]

public bool Completed { getset; }

[DataMember]

public string Message { getset; }

}

 
   

 

[DataContract 어트리뷰트 선언이 직렬화된 문자열]

   

정확한 JSON 형태의 문자열을 보이고 있다.  이제 마지막으로 클라이언트에서는 수신된 문자열을 JSON 객체로 활성화 한 후 적절히 사용하기만 하면 된다.

   

4.2. 자바스크립트에서 JSON 객체로 활성
간단하게 자바스크립트 eval() 함수를 통하여 객체를 활성화 할 수 있으나 eval() 함수는 XSS(Cross Site Scripting) 공격에 취약점을 가질 수 있다. 그러므로 문자열을 JSON 객체로 활성화 하기 위한 Parser를 사용 하는 것이 가장 안전하다.

http://www.json.org 에 방문하면 각 언어별 JSON parser 가 존재하며, 자바스크립트로 제공된 라이브러리를 무료로 받을 수 있다. 이 예제에서는 사이트에서 받은 json2.js를 이용하였다. JSON 객체로 활성화 한 코드는 위에서 이미 보았겠지만 JSON.parse()로 쉽게 활성화 가능하다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함