1 Results for '데이터교환'

  1. 2008.05.20 [TIP] XmlSerializer로 데이터 교환을 가볍고 편리하게

먼저 데모는 다음 파일을 받아보세요.

XmlSerializerTest.zip

XmlSerializer 테스트 프로젝트



실버라이트 애플리케이션이 웹 서버로부터 데이터를 교환 하는 방법에는 몇 가지를 생각해 볼 수 있죠. 웹 서비스, JSON, XmlHttpRequest, 기타 등등...
전 이 중에서 웹 서비스를 즐겨썼는데 왜냐면 웹 서비스는 웹 서비스로 전달되는 데이터 인자를 자동으로 직렬화Serialize하여 SOAP형식으로 만들어주고 데이터를 받을 때에도 서비스 참조만 해주면 자동으로 프락시 클래스를 생성해주기 때문에 서버가 전달해준 데이터 클래스를 클라이언트에서도 그대로 쓸 수 있어서 무지 편리하기 때문이죠.

그러나 웹 서비스는 기본적으로 SOAP의 특성상 데이터 부분 외의 오버헤드가 상당히 심한 편이기도 하고 사람이 직관적으로 이해하기에는 통신 구조가 복잡한 편이라서 간단한 데이터 교환은 단순한 구조의 XML을 만드는 경우도 있죠.

XML을 직접 전송하고 받는 쪽에서 파싱을 하는 과정은 꽤나 귀찮은 작업인데요, 만약 자신이 개발한 서버와 데이터를 교환할 때에는 아주 간단한 방법으로 데이터 클래스를 XML로 직렬화 할 수 있어요.

C#에서는 기본적으로 클래스를 선언할 때 [Serializable] 이라는 어트리뷰트를 추가함으로써 간단하게 해당 개체를 직렬화 할 수 있지만 실버라이트2는 Serializable 어트리뷰트가 제공되지 않죠. 대신 XmlSerializer와 Xml관련 어트리뷰트를 제공하여 비교적 간단하게 직렬화를 구현할 수 있어요.

참고로 XmlSerializer를 쓰기 위해서는 System.Xml과 System.Xml.Serialization 어셈블리를 참조해야 해요.


예를 들어 서버 측에서 DB에서 데이터를 조회하고 다음과 같은 데이터 클래스를 만들었다고 치죠.

public class ArticleData

    {

        [XmlElement]

        public long ID { get; set; }                // ID

        [XmlElement]

        public string Title { get; set; }           // 제목

        [XmlElement]

        public string Content { get; set; }         // 내용

        [XmlElement]

        public string Description { get; set; }     // 주석

        [XmlElement]

        public DateTime RegDate { get; set; }       // 등록 일자

        [XmlElement]

        public int ViewCount { get; set; }          // 조회수

        [XmlElement]

        public string ImageUrl { get; set; }        // 이미지 URL(URI는 사용 불가)

        [XmlElement]

        public bool IsRemoved { get; set; }         // 삭제되었는지 여부

 

        [XmlElement]

        public UserData User { get; set; }          // 사용자 정보

    }

 

    public class UserData

    {

        [XmlElement]

        public string ID { get; set; }              // 사용자 ID

        [XmlElement]

        public string Name { get; set; }            // 사용자 이름

    }


보이는 것처럼 데이터 클래스의 각 프로퍼티에 [XmlElement] 또는 [XmlAttribute] 어트리뷰트를 선언만 하면 일단 준비는 끝. 아주 직관적이게도 [XmlElement] 어트리뷰트가 붙은 프로퍼티는 나중에 XML로 생성될 때 <Element>value</Element>형식으로 표현되고 [XmlAttribute] 어트리뷰트가 붙은 프로퍼티는 <ClassName Attribute="value"></ClassName>형식으로 표현되죠.

여튼 이 데이터 클래스는 XmlSerializer에 의해 직렬화되고 이렇게 직렬화된 문자열은 다음과 같은 XML형태가 되죠.

  <?xml version="1.0" encoding="utf-16" ?>

- <ArticleData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <ID>0</ID>

  <Title>테스트</Title>

  <Content>가나다라 あいうえお 家羅多羅 abcd ♠!@#$</Content>

  <RegDate>2008-05-20T21:32:39.938+09:00</RegDate>

  <ViewCount>100</ViewCount>

  <ImageUrl>images/sample.png</ImageUrl>

  <IsRemoved>false</IsRemoved>

- <User>

  <ID>Gongdo</ID>

  <Name>공도</Name>

  </User>

  </ArticleData>


여기서 문제는 encoding="utf-16"을 실버라이트에서 정상적으로 인식하지 못한다는 점인데요, XML의 인코딩은 utf-8로 설정해야 해요. 바로 다음 코드 처럼요.

// DB나 비즈니스 로직에서 작성된 데이터

ArticleData data = new ArticleData

{

    ID = 0,                 // long

    Title = "테스트",       // string

    Content = "가나다라 あいうえお 家羅多羅 abcd !@#$",  // with unicode string

    Description = null,     // null

    RegDate = DateTime.Now, // DateTime

    ViewCount = 100,        // int

    //Image = new Uri("images/sample.png", UriKind.RelativeOrAbsolute),   // Do not use URI

    ImageUrl = "images/sample.png",

    IsRemoved = false,      // bool

    User = new UserData     // Sub class

    {

        ID = "Gongdo", Name = "공도"

    }

};

 

// 시리얼라이저 작성

XmlSerializer xs = new XmlSerializer(typeof(ArticleData));

string response = null;

 

// 시리얼라이즈 결과를 저장할 스트림

using (MemoryStream ms = new MemoryStream())

{

    // UTF-8 인코딩을 사용하기 위해 XmlTextWriter사용

    using (XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8))

    {

        // 데이터 시리얼라이즈

        xs.Serialize(xtw, data);

        // 기록된 데이터의 처음부터 끝까지 string으로 읽기

        ms.Seek(0, SeekOrigin.Begin);

        using (StreamReader sr = new StreamReader(ms))

        {

            response = sr.ReadToEnd();

        }

    }

}


여튼 이렇게 만들어진 XML 문자열을 응답해주면 실버라이트 측에서는 받은 XML 문자열을 별도의 파싱 코드 없이 XmlSerializer의 역직렬화Deserialize를 통해 데이터 클래스로 얻을 수 있어요.

// WebClient XML데이터 Request/Response 처리

WebClient wc = new WebClient();

wc.OpenReadCompleted += delegate(object sender, OpenReadCompletedEventArgs e)

{

    if (e.Error != null || e.Cancelled)

    {

        // 에러

        return;

    }

    XmlSerializer xs = new XmlSerializer(typeof(ArticleData));

    ArticleData data = xs.Deserialize(e.Result) as ArticleData;

};

wc.OpenReadAsync(uri);


여튼 이 방법은 사실 실버라이트가 [Serializable]을 지원하지 않아서 XSD에 기반한 클래스를 곧바로 사용할 수 없기 때문에 차선으로 선택한 방법이고요, 설계상 썩 좋다고는 할 수 없지만 내가 관리하는 서버와 통신하되 XML로 데이터를 교환하고 싶을 때 아주 유용하게 쓸 수 있는 방법이죠.

신고
Posted by gongdo


티스토리 툴바