본문 바로가기

TechLog

Flash & Asp.net - 2 : Flash 개체와 XML 데이터 연동하기

Flash & Asp.net - 2 : Flash 개체와 XML 데이터 연동하기

첫번째 아티클에 이어서, 이번에는 플래시에서 XML 지원 컴포넌트를 사용해서 ASP.net과 연동하는 방법을 설명합니다.

 

안녕하세요 : )

Flash & Asp.net - 1 : Form 전송으로 Flash 개체와 통신하기에 이은 Flash & Asp.net 두번째 글입니다.

 

지 난 아티클에서는 Form 전송 방법을 사용해서 플래시 개체와 통신하는 방법을 알아보았습니다. Form을 이용한 방식은 일단 개발시에 간단한 메시지만 정의해서 사용할 경우에는 꽤 유용합니다. 하지만 한 개의 aspx에서 여러 형태의 요청을 처리해야 할 경우에 메시지의 정의가 복잡해지고, 데이터 자체의 가독성이 떨어지는데다가, 데이터의 타입을 판별하는 것 조차 어려운 등 여러가지 단점이 있습니다.

 

이 런 상황에서 XML을 사용하게 되면, 요청/응답의 데이터가 XML 문서 형태의 메시지에 가까워져서 보다 데이터 자체의 가독성이 높아지고, 메시지의 요청/응답 형태별로 코드를 작성할 수 있게 됩니다. Flash에서도 XML을 사용할 때의 장점을 수용하기 위해, XML 관련 컴포넌트를 제공하고 있습니다.

 

이 아티클에서는 간단한 요청/응답 XML 메시지를 정의하고, Flash 개체에서 aspx 페이지에 XML 메시지를 전송해서 특정 작업을 요청하고, 그 요청에 대해 XML 메시지로 응답을 받는 샘플을 소개하도록 하겠습니다.

 

이 아티클 또한 VS.net 2003 Flash MX 2004를 기준으로 작성되었음을 먼저 알려드립니다.

 

그럼 시작합니다 : )

 

 

메시지를 정의하면 어떻게 되는건데?

 

요 청/응답 XML 메시지를 정의한다고는 하지만, 사실 이건 그렇게 거창한 작업이 아니다. 프로그래머가 필요한 데이터를 적당히 포장할 수 있는 형태의 XML 문서를 작성할 수 있으면 되는 것이다. 예를 들자면 Kenial이 작성한 XML 메시지는 다음과 같다 :

 

- 요청 메시지

 

 

 

 

<CalculatorMessage Type="RequestAdd">
    <number>1</number>
    <number>3</number>
    <number>4</number>
</CalculatorMessage>

 

 

 

 

- 응답 메시지

 

 

 

 

<CalculatorMessage Type="ResponseAdd">8</CalculatorMessage>

 

 

 

 

 

 

굳 이 설명이 필요한가? 단순히 계산할 숫자(1, 3, 4)를 전송하면 그 결과(8)을 응답해주는 형태의 XML이다. 물론 이 메시지는 별로 쓸만한 결과물이 아니다. 하지만 저런 식으로 메시지의 타입을 지정하고 요청/응답에 대한 메시지를 설계할 수 있다는 것은 큰 규모의 Flash 컴포넌트를 만들어야 할 경우에는 큰 도움이 된다. 만약 위 메시지를 이전 Form 방식으로 전송해서 LoadVars 개체를 사용해 전송받는다면 메시지는 어떻게 될까 :

 

 

 

 

CalculatorMessage=RequestAdd&number=1&number=3&number=4

 

 

 

 

 

숫 자가 여기선 세 개 밖에 없지만, 수십 개의 필드로 나뉘는 데이터를 전송해야 하는 상황이 온다면 메시지를 디버깅하는데만도 꽤 큰 수고가 될 것이다. 게다가 XML로 메시지가 작성되어 있다면, xsd등을 통해서 데이터를 검증할 수도 있는 등, 여러가지 장점이 있다!

 

하 지만 아직도 왜 XML을 요청/응답 메시지로 사용해야 하는지 감이 오지 않는다면, 일단 Kenial을 믿어보고 사용해보기 바란다. 얼마 안 가서 선택이 옳았음을 알게 될 것이다. 이건 Kenial의 몇 년 안되는 개발자 경력을 걸고라도 확실히 말할 수 있다!

 

위의 메시지를 보고서 대강 알았겠지만, 이번 예제는 사칙연산을 하는 메시지를 받아서 처리하는 aspx 페이지를 만드는 것이다. 첫번째 아티클과 마찬가지로, aspx 페이지에서의 작업을 먼저 설명하겠다.

 

 

닷넷의 XML, System.Xml 네임스페이스

 

닷 넷 프레임워크에서는 System.Xml 네임스페이스를 통해 XML 기능을 지원하는 여러가지 클래스를 제공한다. 이 예제에서는 파싱을 좀 더 간편하게 하기 위해 XmlDocument 클래스를 주로 사용하기로 한다. XmlDocument 클래스 자체에 대한 설명은 거의 생략하고 넘어갈 예정이므로, 해당 클래스에 대한 사용법은 MSDN 등을 참고하시길(무책임)

 

aspx 파일의 소스는 다음과 같다 :

 

using System.Xml;

...

private void Page_Load(object sender, System.EventArgs e)

{

    Response.Expires=0;

    XmlDocument xReceiveDoc = new XmlDocument();

    xReceiveDoc.LoadXml(Server.UrlDecode(Request.Form.ToString()));

 

    System.Xml.XmlNode node;

    

    node = xReceiveDoc.SelectSingleNode("CalculatorMessage");

    bool bWrongXMLMessage = false;

    XmlDocument xSendDoc = new XmlDocument();

    xSendDoc.PreserveWhitespace = false;

    System.Xml.XmlElement element;

    System.Xml.XmlAttribute attr;

 

    if(node==null)

    {

        bWrongXMLMessage = true;

    }

    else

    {

        string strCalcType = node.Attributes["Type"].Value;

        switch(strCalcType)

        {

            case "RequestAdd":

                int sum = 0;

                node = node.FirstChild;

                while(node!=null)

                {

                    if(node.Name=="number")

                    {

                        sum += int.Parse(node.InnerText);

                    }

                    node = node.NextSibling;

                }

            

                element = xSendDoc.CreateElement("CalculatorMessage");

                attr = xSendDoc.CreateAttribute("Type");

                attr.Value = "ResponseAdd";

                element.Attributes.Append(attr);

                element.AppendChild(xSendDoc.CreateTextNode(sum.ToString()));

                xSendDoc.AppendChild(element);

                break;

            case "RequestSubtract":

                int minuend = 0;

                node = node.FirstChild;

                while(node!=null)

                {

                    if(node.Name=="number")

                    {

                        minuend = int.Parse(node.InnerText);

                        break;

                    }

                    node = node.NextSibling;

                }

                node = node.NextSibling;

                while(node!=null)

                {

                    if(node.Name=="number")

                    {

                        minuend -= int.Parse(node.InnerText);

                    }

                    node = node.NextSibling;

                }

            

                element = xSendDoc.CreateElement("CalculatorMessage");

                attr = xSendDoc.CreateAttribute("Type");

                attr.Value = "ResponseSubtract";

                element.Attributes.Append(attr);

                element.AppendChild(xSendDoc.CreateTextNode(minuend.ToString()));

                xSendDoc.AppendChild(element);

                break;

            default:

                bWrongXMLMessage = true;

                break;

            

        }

    }

    if(bWrongXMLMessage)

    {

        element = xSendDoc.CreateElement("CalculatorMessage");

        attr = xSendDoc.CreateAttribute("Type");

        attr.Value = "ResponseError";

        element.Attributes.Append(attr);

        element.AppendChild(xSendDoc.CreateElement("OriginalMessage"));

        element.FirstChild.AppendChild(xSendDoc.CreateTextNode(Request.Form.ToString()));

        xSendDoc.AppendChild(element);

    }

    xSendDoc.Save(Response.OutputStream);

    Response.End();

}

...

    XmlReceiver.aspx.cs

 

Kenial이 지금껏 쓴 아티클의 소스 중 가장 긴 소스가 아닐까한다. (ctrl + c, v 조차 귀찮은 유저 여러분들을 위해 이번 소스는 첨부하도록 하겠다) 특별히 설명해야 할 코드들만 짚고 넘어가보도록 하겠다.

 

Request.Form.ToString() 을 사용하게 되면 Form 데이터로 들어온 모든 문자열을 반환한다. 언뜻 들으면 무슨 말인지 잘 감이 안 오겠지만, 설명하면 다음과 같다: Form 데이터를 Request["data"]으로 받는다는 것은, Request 객체에 든 Form 객체의 데이터가 "data=xxxx" 형태로 들어있는 것을 뜻한다. 그러므로 Form 객체의 데이터를 각 필드 이름(표현이 정확하지 않지만 이해 바란다)으로 나눠서 받는게 일반적이지만, Flash에서 지원하는 XML 컴포넌트는 필드이름을 사용하지 않고 Form 데이터 전체에 XML 문서 내용을 실어서 전송하게 된다. 그러므로 위와 같이 Form.ToString()을 사용해서 Form 데이터 전체를 받으려고 하는 것이다.

 

결과를 비교하자면 다음과 같다 :

 

- Form 전송(LoadVars 개체를 사용할 때)

 

 

 

 

data1=1234&data2=2345

...
Request["data1"];  // "1234"
를 얻음
Request["data2"];  // "2345"
를 얻음

 

 

 

 

-Form 전송(XML 지원 컴포넌트를 사용할 때)  

 

 

 

 

<data1>1234</data1><data2>2345</data2>

...
// "<data1>1234</data1><data2>2345</data2>"
를 얻음
Request.Form.ToString();

 

 

 

 

중간의 switch 문은 CalculatorMessage Type 속성에 따라 각 동작에 대한 처리로 분기할 수 있도록 해 준다. 그리고 그 결과는 xSendDoc에 담겨 Flash로 전달된다.

 

bWrongXMLMessage XML 요청 메시지의 형식이 틀렸는지 검사해서 틀렸을 경우에 에러 메시지를 리턴하기 위해 정의한 bool 변수이다. 원래대로라면 xsd를 사용해 검증해야 하는 것이 좋겠으나, 여기서 중요한 로직은 아니므로 넘어가도록 하겠다.

 

마 지막의 xSendDoc.Save(Response.OutputStream) 코드는 Page Response 개체의 출력 스트림을 가져와, 전송될 XML의 내용을 최종적으로 Flash로 전달되도록 하는 코드이다. (스트림에 대한 설명은 이 범위를 넘으므로 생략하겠다)

 

 

Flash XML, XML Class

 

Flash 5에서부터 지원되어 온 XML 지원 클래스는, 액션스크립트에서 XML이란 네이밍을 가지고 있다. (심플하기 그지없다) XMLConnector라는 schema xpath 등 여러가지 새로운 기능을 지원하는 컴포넌트가 있으나, 일단 간단한 예제를 보여주기 위해 여기서는 XML 클래스를 사용하도록 하겠다.

 

Flash에서 다음과 같은 폼을 만든다. Button 컴포넌트 세개와 TextArea 컴포넌트를 배치하며, TextArea 컴포넌트에는 txtResult라는 Instance Name을 준다 :

 

   

 

그리고 각 버튼에 다음과 같은 코드를 입력한다 (역시 이것도 코드가 좀 길어졌다) :

 

on(release)

{

    // 보낼 XML 준비

    sendXML = new XML();

 

    sendXMLElement = sendXML.createElement("CalculatorMessage");

    sendXMLElement.attributes.Type = "RequestAdd";

    sendXML.appendChild(sendXMLElement)

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("1"));

    sendXML.firstChild.appendChild(sendXMLElement);

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("3"));

    sendXML.firstChild.appendChild(sendXMLElement);

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("4"));

    sendXML.firstChild.appendChild(sendXMLElement);

    

    recvXML = new XML();

    recvXML.onLoad = onReceive; 

    sendXML.sendAndLoad("http://localhost/flashtest/XmlReceiver.aspx", recvXML);

 

    _root.txtResult.text = "Send : " + sendXML.toString() + "\n";

 

    function onReceive(result)    {

        _root.txtResult.text += "Received : " + recvXML.toString() + "\n";

    };   

}

    '더하기' 버튼

 

on(release)

{

    // 보낼 XML 준비

    sendXML = new XML();

 

    sendXMLElement = sendXML.createElement("StrangeMessage");

    sendXMLElement.attributes.Type = "RequestAdd";

    sendXML.appendChild(sendXMLElement)

    

    recvXML = new XML();

    recvXML.onLoad = onReceive; 

    sendXML.sendAndLoad("http://localhost/flashtest/XmlReceiver.aspx", recvXML);

 

    _root.txtResult.text = "Send : " + sendXML.toString() + "\n";

 

    function onReceive(result)    {

        _root.txtResult.text += "Received : " + unescape(recvXML.toString()) + "\n";

    };  

}

    '낯선메시지' 버튼

 

on(release)

{

    // 보낼 XML 준비

    sendXML = new XML();

 

    sendXMLElement = sendXML.createElement("CalculatorMessage");

    sendXMLElement.attributes.Type = "RequestSubtract";

    sendXML.appendChild(sendXMLElement)

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("3"));

    sendXML.firstChild.appendChild(sendXMLElement);

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("4"));

    sendXML.firstChild.appendChild(sendXMLElement);

    sendXMLElement = sendXML.createElement("number");

    sendXMLElement.appendChild(sendXML.createTextNode("10"));

    sendXML.firstChild.appendChild(sendXMLElement);

    

    recvXML = new XML();

    recvXML.onLoad = onReceive; 

    sendXML.sendAndLoad("http://localhost/flashtest/XmlReceiver.aspx", recvXML);

 

    _root.txtResult.text = "Send : " + sendXML.toString() + "\n";

 

    function onReceive(result)    {

        _root.txtResult.text += "Received : " + recvXML.toString() + "\n";

    };  

}

    '빼기' 버튼

 

사 실 코드 내용만 보자면, 기본적으로 Form 전송을 이용하고 있기 때문에 (내부적으로는 POST 방식으로 전송한다) 첫번째 아티클과 그다지 차이는 없다. 조금 다른 것이라면 여기서도 aspx 페이지에서와 마찬가지로 Form 내용 전체를 가져오는데에 개체의 속성을 이용하지 않고 toString() 메서드로 Form 데이터 전체를 가져온다는 점에서 차이가 있다.

 

XML 문서 내용을 생성하는 메서드는 굳이 설명하지 않아도 이해가 갈 것이라고 생각하고 넘어가겠다.

 

실행하면 결과는 다음과 같다 :

 

   

    더하기 메시지에 대한 응답

 

   

    낯선 메시지에 대한 응답(응답 에러를 반환하고 있다)

 

   

    빼기 메시지에 대한 응답

 

 

정리

 

XML 메시지 생성 때문에 코드 길이만 잔뜩 길어져버린 아티클이었습니다. 헉헉..

 

사 실 이전 Form 전송 방식은 이 XML 메시지 전송 방법을 알기 위한 사전지식 성격이 강했습니다. (물론, 그 자체도 쓸모있는 방법이긴 하지만 말입니다) XML 메시지가 전송되고 그에 대한 응답을 받는 개념이 눈에 들어오면, Flash 뿐만이 아니라 어떤 프로그램에서도 응용할 수 있는 유용한 기술이 됩니다.

 

이 아티클 역시 수많은 이종개발자(?)를 양산하는데에 도움이 되길 바라며.

 

그럼 : )