delphi 2010 datasnap - softwarecatalog.co.kr · delphi 2010의 새로운 datasnap 클래스...

54
기술 백서 Delphi 2010 DataSnap 밥 슈워트(Bob Swart) – 밥 슈워트 교육&컨설팅 (eBob42) 2009년 12월 Corporate Headquarters Asia-Pacific Headquarters DEVGEAR 100 California Street, 12th Floor L7. 313 La Trobe Street 서울특별시 서초구 San Francisco, California 94111 Melbourne VIC 3000 반포동 743-14 Australia 4층 데브기어

Upload: others

Post on 22-Oct-2019

11 views

Category:

Documents


0 download

TRANSCRIPT

기술 백서

Delphi 2010 DataSnap

밥 슈워트(Bob Swart) – 밥 슈워트 교육&컨설팅 (eBob42)

2009년 12월

Corporate Headquarters Asia-Pacific Headquarters DEVGEAR

100 California Street, 12th Floor L7. 313 La Trobe Street 서울특별시 서초구

San Francisco, California 94111 Melbourne VIC 3000 반포동 743-14

Australia 4층 데브기어

Delphi 2010의 새로운 DataSnap

DataSnap 히스토리

델파이 3 에서 처음 등장한 MIDAS는 델파이 4와 델파이 5에서 각각 MIDAS II 와 MIDAS III로

업그레이드되었으며, COM에 기초하는 리모트 데이터 모듈을 작성하는 강력한 방법으로서 TCP/IP, HTTP

와 COM (DCOM) 연결 방법을 제공했었습니다. 델파이 6에서는 MIDAS가 DataSnap이라는 이름으로

바뀌었으며, 이 프레임워크는 델파이 2007까지 거의 그대로였습니다.

델파이 2009에서는 DataSnap에 새로운 아키텍처를 도입하여 COM에 대한 의존성을 배제하고 더 가벼운

연결 방식을 사용하는 리모트 서버를 개발할 수 있게 하였습니다. 이 DataSnap 2009에서는 오직 TCP/IP

통신만을 사용할 수 있었지만, 델파이 프리즘 2009로 .NET 클라이언트를 작성 할 수 있는 기능이

추가되었습니다.

델파이 2010에서는 DataSnap 2009의 기반에 새로운 기능들을 추가하여 이 프레임워크를 확장하였습니다.

2010 버전에서는 새 애플리케이션 타입들을 선택할 수 있는 두 개의 위저드 (일반 애플리케이션 / 윈도우

서비스 / 콘솔, ISAPI / CGI / Web App Debugger), HTTP/HTTPS 통신 프로토콜, HTTP 인증, 클라이언트

콜백 함수, REST 와 JSON의 지원, 압축을 지원하는 필터 등의 기능들이 추가되었습니다.

1.1 DataSnap 예제 데이터

이 문서에서는 여러분과 함께 여러 예제를 작성해볼 것입니다. 델파이에서는 DBX4, dbGo for ADO 등

여러 가지 데이터 액세스 기술들로 여러 데이터베이스들을 지원하지만, 편의상 DBX4와 BlackfishSQL 데이터베이스, 그리고 employee.jds 데이터베이스 파일을 사용할 것입니다.

이 파일은 Windows XP의 경우에는 C:\Documents and Settings\All Users\Documents\RAD Studio\7.0\Demos\database\databases\BlackfishSQL 위치에, Windows Vista나 Windows 7의

경우에는 C:\Users\Public\Documents\RAD Studio\7.0\Demos\database\databases \BlackfishSQL 위치에 있습니다. 아래의 스크린샷들을 보면 알겠지만, 저는 운영체제로 Windows 7

프로페셔널을 사용하고 있으며, 추가적으로 DataSnap ISAPI 서버를 테스트하기 위해 Windows Server

2008 웹 에디션을 사용합니다.

2. DataSnap Windows 애플리케이션

DataSnap 2010 은 VCL 폼 애플리케이션, 윈도우 서비스 애플리케이션, 그리고 콘솔 애플리케이션 등 3

가지 윈도우 애플리케이션 타입들을 지원합니다. 여기서는 각각의 장점, 차이점과 이러한 타입들을

사용하기 위한 최적의 경우 등을 살펴보겠습니다.

지금부터 만들어 볼 DataSnap 서버 및 클라이언트 예제에서는 TDSServer, TDSServerClass,

TDSTCPServerTransport, TDSHTTPService, TDSHTTPServiceAuthenticationManager,

TDSHTTPWebDispatcher 등의 컴포넌트들을 사용하게 될 것이며, 커스텀 서버 메소드와

TDSServerModule 클래스도 다룰 것입니다.

TCP, HTTP 통신 프로토콜들에 대해 각각의 효과와 잠재적인 장점에 대해서 살펴볼 것입니다. DataSnap

서버 객체의 라이프타임에 대한 몇가지 옵션들(서버, 세션, 인보케이션)에 대해서도 각각의 효과와 실제

사용시 권장 사항들과 함께 언급하겠습니다. 마지막으로 몇 가지 배포에 관한 이슈들도 살펴볼 것입니다.

2 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

2.1. DataSnap 서버 예제

델파이 2010의 오브젝트 리포지토리에는 두 가지의 DataSnap 서버 위저드가 있습니다. 하나는 Windows

기반의 DataSnap 서버 프로젝트를 위한 것이며, 다른 하나는 IIS(Internet Information Services) 등의 웹

서버로 호스팅할 웹 브로커 기반의 DataSnap 서버 프로젝트를 위한 것입니다. 앞의 것부터 시작해보도록

하겠습니다.

델파이 2010의 메뉴에서, File | New – Other 메뉴를 선택하여 오브젝트 리포지토리를 띄우면 DataSnap

Server 위저드들을 찾을 수 있습니다. 오브젝트 리포지토리의 DataSnap Server 페이지에서 DataSnap

Server, DataSnap WebBroker Server, Server Module 등의 3 개의 아이콘을 보실 수 있습니다.

첫 번째 아이콘을 더블클릭하면 다음과 같은 다이얼로그가 나타납니다. (다른 두 개의 아이콘은 이후에

다룰 것입니다)

3 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

이 다이얼로그의 첫 섹션에서는 프로젝트의 타겟을 선택합니다. 디폴트로 선택되어 있는 것은 메인 화면을

갖는 일반 애플리케이션인 VCL Forms Application입니다. 두 번째는 Console Application으로, 콘솔

윈도우를 제공하여 요청과 응답이 어떻게 일어나고 있는지 추적하는 데에 더 적합합니다 (간단히 writeln

문장으로 서버 애플리케이션 안에서 어떤 작업이 수행되고 있는지 표시할 수 있습니다).

두 가지 애플리케이션 타입 모두 데모나 초기 개발용으로는 적합하지만, 최종적으로 DataSnap 서버

애플리케이션을 배포하는 경우에는 이상적이지 않을 것입니다. 새로운 DataSnap 구조는 더 이상 COM에

기반하지 않기 때문에, 클라이언트 연결 요청으로 DataSnap 서버 애플리케이션을 실행시킬 수가

없습니다. 따라서 들어오는 클라이언트 요청을 처리하기 위해서는 DataSnap 서버는 이미 설치 및

실행되고 있어야만 합니다. 또, 만일 들어오는 요청들을 언제나 항상 (24시간 x 7일) 처리하기 원한다면

DataSnap 서버 애플리케이션도 역시 마찬가지로 24시간 x 7일 실행되고 있어야 합니다. 일반

애플리케이션이나 콘솔 애플리케이션의 경우, 이 것은 윈도우에 로그인하고 DataSnap 서버

애플리케이션을 실행해야 한다는 의미가 되며, 이것은 이상적인 방법이 아닙니다.

세 번째 선택이 바로 이와 같은 경우에 더 적절한 방법입니다. Windows Service Application은 컴퓨터에

로그인할 필요 없이 컴퓨터가 시작될 때 자동적으로 실행되도록 설정할 수 있습니다. 서비스

애플리케이션의 약점은 기본적으로 데스크탑에서 보이지 않으며, 디버그 하기가 조금 어렵다는 점입니다.

그러나 이 세 가지 선택으로부터 최선의 결과를 내기 위해, VCL Forms DataSnap 서버 애플리케이션,

Console DataSnap 서버 애플리케이션, Service DataSnap 서버 애플리케이션 등을 모두 포함하는

프로젝트 그룹을 작성하는 방법을 잠시 후에 보여드릴 것입니다. 세 프로젝트는 동일한 커스텀 서버

메소드를 공유하여 동일한 DataSnap 서버 애플리케이션을 여러분이 필요한 대로 3 가지 서로 다른

타겟으로 컴파일 및 배포할 수 있게 됩니다.

New DataSnap Server 다이얼로그의 두 번째 섹션은 우리가 사용할 수 있는 통신 프로토콜들을

보여줍니다. DataSnap 2009에 비하면 HTTP 통신과 그에 더하여 HTTP 인증을 사용할 수 있게

되었습니다. 가장 유연성 있게 하기 위해서는, 여기에 있는 모든 옵션을 체크하기를 권합니다. 그러면

4 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

TCP/IP 와 HTTP를 모두 사용할 수 있게 되며, 또한 HTTP와 연관하여 HTTP 인증을 사용할 수 있게

됩니다.

New DataSnap Server 다이얼로그의 마지막 섹션은 제가 보기에 이미 잘 구성되어 있습니다. 서버 메소드

클래스를 자동으로 생성해주며, TPersistent, TDataModule, TDSServerModule 중에서 조상 타입을 선택

할 수도 있습니다. 마지막 선택인 TDSServerModule은 시작하면서 바로 메소드에 관한 RTTI를 가능하게

해주기 때문에 최선의 선택입니다. 물론 일반적인 TDataModule이 충분하다고 느낄 수도 있으며

데이터셋이나 넌비주얼 컨트롤들을 사용하지 않는다면 TPersistent 도 충분할 수 있습니다.

유닛 DSServer.pas에서 발췌한 부분에서 TDSServerModule와 TProviderDataModule 사이의 관계를

보여주며, TDataModule로부터 파생되었습니다.

TDSServerModuleBase = class(TProviderDataModule) public procedure BeforeDestruction; override; destructor Destroy; override; end; {$MethodInfo ON} TDSServerModule = class(TDSServerModuleBase) end; {$MethodInfo OFF}

조상 클래스로 뭘 선택할지에 대해 특별한 생각이 없다면 TDSServerModule로 선택하면 됩니다.

2.1.1. 멀티 타겟 프로젝트 그룹 – VCL Forms 애플리케이션

약속한 대로, 이제 멀티 타겟 DataSnap 서버 프로젝트 그룹을 작성해보겠습니다. 먼저, DataSnap 서버로

VCL Forms Application을 선택하고 모든 프로토콜을 선택합니다.

5 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

Project1.dproj이라는 이름의 프로젝트가 생성되고 ServerContainerUnit1.pas, ServerMethodsUnit1.pas,

Unit1.pas라는 이름을 갖는 세 유닛이 포함되어 있을 것입니다. File | Save Project As 메뉴를 선택하여,

더 적절한 파일 이름을 지정합니다. Unit1.pas는 MainForm.pas로, ServerContainerUnit1.pas는

ServerContainerUnitDemo.pas로, ServerMethodsUnit1.pas는 ServerMethodsUnitDemo.pas로 각각

저장하고, Project1.dproj는 DataSnapServer.dproj로 저장합니다.

차후에 프로젝트 그룹에 콘솔 애플리케이션과 서비스 애플리케이션을 추가할 것입니다. 먼저, 현 시점에서

가지고 있는 것들을 살펴보고 프로젝트를 컴파일 해봅시다. 지금 바로 DataSnapServer 프로젝트를

컴파일해보면 에러 메시지 하나를 보게 될 것입니다. 자동 생성된 유닛 ServerMethodsUnit1.pas 의

이름을 변경했기 때문입니다. 이 에러는 ServerMethodsUnit1.pas 를 ServerMethodsUnitDemo 로

저장했는데, ServerContainerUnitDemo.pas 유닛의 구현 부분 (라인 30)의 uses 절에서

ServerMethodsUnit1 유닛을 uses 했기 때문에 발생합니다.

이 문제를 해결하기 위해서, uses 절에서 변경된 파일 이름대로 수정하고 다시 컴파일 합니다. 이번에는

TServerMethods1 클래스를 지정한 ServerMethodsUnit1 의 37 라인에서 에러가 발생할 것입니다.

ServerMethodsUnit1 를 ServerMethodsUnitDemo 로 수정하면, 더 이상 문제 없이 DataSnap 서버

프로젝트를 컴파일 할 수 있을 것입니다.

ServerContainerUnitDemo 유닛의 구현 부분이 아래와 같이 새롭게 보일 것 입니다.

implementation uses Windows, ServerMethodsUnitDemo; {$R *.dfm} procedure TServerContainer1.DSServerClass1GetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := ServerMethodsUnitDemo.TServerMethods1; end; end.

2.1.1.1. ServerContainerUnitDemo

IServerContainerUnitDemo 유닛의 디자인 탭을 선택해서 보면, TDSServer, TDSServerClass,

TDSTCPServerTransport (TCP/IP 통신), TDSHTTPService (HTTP 통신) 그리고

TDSHTTPServiceAuthenticationManager (HTTP 인증) 등 5 개의 컴포넌트를 볼 수 있습니다.

처음 두 개는 항상 포함되어 있으며, 나머지 세 개는 위저드에서 선택했던 통신 프로토콜 옵션에 따라

추가되거나 추가되지 않을 수 있습니다.

6 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

2.1.1.1.1. TDSServer

TDSServer 컴포넌트는 AutoStart, HideDSAdmin, Name, Tag 등 네 개의 속성들을 가지고 있습니다.

AutoStart 속성은 기본값으로 True로 지정되어 있으며, 폼이 생성된 직후 DataSnap 서버가 자동으로

시작하는 것을 의미합니다. AutoStart를 True로 설정하지 않는 경우에는 여러분이 Start 메소드를

호출하여 수동으로 시작할 수 있으며, 또한 항상 Stop 메소드를 호출해야만 합니다. 만일 DataSnap

서버가 이미 시작되었는지 알아보기 위해서는 Started 함수를 사용하면 됩니다.

HideDSAdmin 속성은 기본값으로 False로 지정되어 있습니다. True로 지정하면 이 DataSnap 서버에

연결하는 클라이언트들은 TDSAdmin 클래스로의 기본 내장 서버 메소드들을 호출 할 수 없게 됩니다.

TDSAdmin 클래스는 실제 클래스는 아니며, 호출 가능한 TDSAdmin 메소드들은 DSNames 유닛에

선언되어 있습니다.

TDSAdminMethods = class public const CreateServerClasses = 'DSAdmin.CreateServerClasses'; const CreateServerMethods = 'DSAdmin.CreateServerMethods'; const FindClasses = 'DSAdmin.FindClasses'; const FindMethods = 'DSAdmin.FindMethods'; const FindPackages = 'DSAdmin.FindPackages'; const GetPlatformName = 'DSAdmin.GetPlatformName'; const GetServerClasses = 'DSAdmin.GetServerClasses'; const GetServerMethods = 'DSAdmin.GetServerMethods'; const GetServerMethodParameters = 'DSAdmin.GetServerMethodParameters'; const DropServerClasses = 'DSAdmin.DropServerClasses'; const DropServerMethods = 'DSAdmin.DropServerMethods'; const GetDatabaseConnectionProperties = 'DSAdmin.GetDatabaseConnectionProperties'; end;

TDSServer 컴포넌트는 OnConnect, OnDisconnect, OnError, OnPrepare, OnTrace 등 5 개의 이벤트를

가지고 있습니다. 여러분은 로그 파일에 텍스트를 써넣는 등의 여러 상황에 대응하기 위해서 이러한

이벤트 핸들러를 작성할 수 있습니다.

OnConnect, OnDisconnect, OnError 와 OnPrepare 이벤트들은 각각 TDSEventObject로부터 파생된

타입의 인자를 가지고 있으며, 이 조상 타입은 DxContext, Transport, Server, DbxConnection 속성을

7 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

포함하고 있습니다. OnConnect와 OnDisconnect의 인자 타입인 TDSConnectEventObject 타입은 그에

더하여 ConnectionProperties와 ChannelInfo 속성을 가지고 있습니다. OnError 이벤트의 인자 타입인

TDSErrorEventObject에는 발생한 예외를 가리키는 Error 속성을 가지고 있으며, OnPrepare 이벤트의

인자 타입인 TDSPrepareEventObject는 MethodAlias와 ServerClass 속성을 가지고 있습니다.

OnTrace 이벤트 핸들러는 TDBXTraceInfo 타입의 인자를 가지고 있습니다. 이벤트를 더블 클릭하여 자동

생성된 OnTrace 핸들러는 코드가 에러로 인식되는데(붉은 색 밑줄), TDBXTraceInfo와 CBRType 타입을

컴파일러가 인식하지 못하기 때문입니다. 이 것을 해결하기 위해서는, DBXCommon 유닛(TDBXTraceInfo

타입에 대해)과 DBCommonTypes 유닛(CBRType에 대해)을 추가하면 됩니다.

OnConnect 이벤트 핸들러가 실행되는 중에는 연결에 대한 ChannelInfo 인자를 살펴 볼 수 있습니다.

아래 예에서는 사용자 함수 LogInfo로 연결 정보를 로그 파일에 써넣습니다.

procedure TServerContainer1.DSServer1Connect( DSConnectEventObject: TDSConnectEventObject); begin LogInfo('Connect ' + DSConnectEventObject.ChannelInfo.Info); end;

OnTrace 이벤트 핸들러에서는 서버가 하고 있는 작업에 대한 정보를 얻기 위해서 TraceInfo.Message 의

내용을 로그에 써넣을 수 있습니다.

function TServerContainer1.DSServer1Trace(TraceInfo: TDBXTraceInfo): CBRType; begin LogInfo('Trace ' + TraceInfo.CustomCategory); LogInfo(' ' + TraceInfo.Message); Result := cbrUSEDEF; // take default action end;

서버 측과 별개로, 클라이언트 측에서는 TSQLConnection 컴포넌트에 연결된 TSQLMonitor 컴포넌트를

사용하여 DataSnap 클라이언트와 서버 사이의 커뮤니케이션을 추적할 수 있다는 점에 알아둡시다. (이

DataSnap 서버에 대한 클라이언트를 작성할 때 보여드릴 것입니다).

추적 결과는 다음과 비슷할 것입니다.

17:05:55.492 Trace 17:05:55.496 read 136 bytes:{"method":"reader_close","params":[1,0]} {"method":"prepare","params":[-1,false,"DataSnap.ServerMethod", "TServerMethods1.AS_GetRecords"]} 17:05:55.499 Prepare

보시는 것처럼, TraceInfo.Message는 호출되는 메소드 뿐만 아니라 바이트 수에 대한 정보도 포함하고

있습니다.

2.1.1.1.2. TDSServerClass

TDSServerClass는 원격의 클라이언트에 published 메소드를 노출시키기 위해 사용되는 서버 측의

클래스를 지정하는 역할을 하는 컴포넌트입니다. (동적 메소드 요청을 사용합니다)

TDSServerClass 컴포넌트는 TDSServer 컴포넌트와 연결하는 Server 속성을 가지고 있습니다. Name 과

Tag 속성을 제외하고, 다른 중요한 속성은 LifeCycle 속성입니다. 디폴트로 Session으로 지정되어있으며,

다른 값으로 Server 혹은 Invocation으로 설정할 수 있습니다. 클래스의 하나의 인스턴스가, Server의 경우

서버의 전체 라이프타임 동안, Session은 DataSnap 세션의 라이프타임 동안, Invocation은 메소드의 단일

요청 동안 사용된다는 것을 의미합니다. Session은 서버로 들어오는 각 커넥션이 각각 자신만의 서버

8 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

클래스 인스턴스를 갖게 된다는 것을 의미합니다. Invocation으로 값을 바꾸면 상태 정보를 가지지 않는

stateless 서버 클래스가 됩니다. 예를 들어 CGI 웹 서버 애플리케이션(이 타입은 stateless 하고 각

요청마다 로드/언로드 하게 됩니다)을 배포하려는 경우 유용할 것입니다. 여러분이 LifeCycle의 값을

Server로 수정한다면, 서버 클래스의 단일 인스턴스가 들어오는 모든 커넥션과 요청에 대해 공유되는 것을

의미합니다. 이 경우는 예를 들면 요청의 수를 카운트하려는 경우에 유용할 것입니다. 그러나 반드시 멀티

쓰레딩 문제가 없는 경우여야만 합니다(복수의 요청이 동르어와서 동시에 처리되어야만 하는 경우).

TDSServerClass는 네 개의 이벤트를 가지고 있는데, OnCreateInstance, OnDestroyInstance (이 두

이벤트는 인스턴스가 생성되거나 파괴되었을 때 발생합니다), OnGetClass, OnPrepare 입니다.

OnPrepare 이벤트 핸들러는 서버 메소드를 준비하기 위해서 사용됩니다.

델파이 2010이나 델파이 2009에서 TDSServerClass 컴포넌트를 컨테이너에 수동으로 위치시키는 경우,

서버로부터 클라이언트로 “ 원격” 이 되는 클래스를 지정하기 위해 OnGetClass 이벤트를 구현해야만

합니다. 그러나 델파이 2010의 DataSnap 위저드는 다음과 같이 OnGetClass 이벤트 핸들러를 자동으로

구현해줍니다.

procedure TServerContainer1.DSServerClass1GetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := ServerMethodsUnitDemo.TServerMethods1; end;

우리가 자동으로 생성된 유닛 ServerMethodsUnit1을 ServerMethodsUnitDemo.pas로 이름을 바꾸었을

때, 바로 이 부분이 수정해야 했던 코드였죠.

2.1.1.1.3. TDSTCPServerTransport

TDSTCPServerTransport 컴포넌트는 DataSnap 서버와 DataSnap 클라이언트 사이에 통신을 담당하는

컴포넌트로서, TCP/IP 통신 프로토콜을 사용합니다.

TDSTCPServerTransport 컴포넌트에는 BufferKBSize, Filters (델파이 2010에서 추가됨), MaxThreads,

PoolSize, Port, Server 등 5개의 중요한 속성이 있습니다.

BufferKBSize 속성은 통신에 필요한 버퍼의 사이즈를 지정하고, 기본으로 32 (KB)로 지정됩니다. Filters

속성에서는 전송 필터(transport filter)들을 지정할 수 있는데, 4장에서 자세히 다룰 것입니다.

MaxThreads 속성은 스레드의 최대 수를 지정할 수 있습니다(디폴트로 최대 수 제한이 없는 0으로

설정되어 있음). PoolSize은 커넥션 풀링을 가능하게 하기 위해 사용할 수 있으며, Port 속성은 서버가

클라이언트에 연결하기 위해 사용하는 TCP/IP 포트를 지정하기 위해 사용됩니다(이 속성을 수정하면

이후에 DataSnap 클라이언트에서도 수정해야만 합니다).

Server 속성은 TDSServer 컴포넌트를 가리킵니다. TDSTCPServerTransport 컴포넌트에는 이벤트는

없습니다.

2.1.1.1.4. TDSHTTPService

TDSHTTPService는 HTTP 프로토콜을 사용하여 DataSnap 서버와 DataSnap 클라이언트 사이에 통신을

하는 컴포넌트입니다.

TDSHTTPService 컴포넌트에는 Name 과 Tag 속성 외에 Active, AuthenticationManager, DSHostname,

DSPort, Filters, HttpPort, RESTContext, Server, ServerSoftware (읽기 전용) 속성 등 9 개의 속성이

있습니다.

9 Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

Active 속성은 DSHTTPService 가 들어오는 요청에 대해 연결 대기(listen)할 것인지 지정합니다. 디자인

시점에 True로 지정할 수 있지만, 이렇게 하면 DataSnap 서버 애플리케이션이 실행 시에 시작하는 것을

막게 될 것입니다. (같은 포트를 사용하는 액티브 DSHTTPService 컴포넌트가 하나만 존재할 수 있는데,

디자인 시에 이미 액티브 된 것이 있기 때문에 실행 시에 시작할 수 가 없게 됩니다) TDSHTTPService를

시작하는 가장 좋은 방법은, TServerContainer의 OnCreate 이벤트 핸들러에서 Active 속성을 True로

지정하는 것입니다.

procedure TServerContainer1.DataModuleCreate(Sender: TObject); begin DSHTTPService1.Active := True; end;

AuthenticationManager 속성은 HTTP 인증 처리에 관한 관리 컴포넌트를 지정하는데 시용되며 우리

예제에서는 이미 TDSHTTPServiceAuthenticationManager 컴포넌트와 연결되어 있습니다. 이 컴포넌트는

2.1.1.1.5 장에서 더 자세히 다루겠습니다.

DSHostname 및 DSPort 속성은 연결할 DataSnap 서버를 지정하는데 사용되는데, Server 속성이

지정되지 않았을 경우에만 사용될 수 있습니다. 대부분의 경우 Server 속성을 TDSServer 컴포넌트로

연결합니다.

Filters 속성은 전송 필터들을 지정할 수 있는데, 4 장에서 자세히 다루게 될 것입니다.

HttpPort 속성은 DSHTTPService 컴포넌트가 들어오는 커넥션을 수신 대기하는 포트를 지정하기 위해

사용됩니다. 디폴트로 값이 80으로 설정되어 있는데, 여러분이 웹 서버(IIS 등)가 설치되어 있는

컴퓨터에서 개발하는 경우 다른 값으로 변경해야만 합니다. 웹 서버가 이미 포트 80을 사용하고 있기

때문에, TDSHTTPService 컴포넌트가 포트 80으로 수신할 수 없기 때문입니다. 애플리케이션을

실행하려고 할 때 에러가 발생할 것입니다.

RESTContext 속성은 REST 서비스로 DataSnap 서버를 호출하기 위해 사용될 수 있는 REST 컨텍스트

URL를 지정합니다. 디폴트 값으로 RESTContext는 “ rest” 로 설정되어 있으며, 이것은 우리가 서버를

http://localhost/datasnap/rest/..로 호출할 수 있다는 것을 의미합니다. 6 장에서 REST, JSON 과 콜백

메소드에 대해 설명할 때 보여드릴 것입니다.

마지막으로, Server 속성은 같은 컨테이너에 있는 TDSServer 컴포넌트로 연결되어야만 합니다. 만일

Server 속성을 연결하지 않으려고 한다면, TCP를 사용하는 DataSnap 서버와 연결하기 위하여

DSHostname 과 DSPort 속성을 사용할 수 있습니다. Server 속성이 지정되어 있으면 DSHostname와

DSPort 속성은 무시됩니다.

TDSHTTPService 컴포넌트는 5 개의 이벤트를 갖는데 4 개는 REST와 관련된 것이고 하나는 Trace 관련

이벤트입니다. REST 이벤트들은 6 장에서 자세히 다루겠습니다.

OnTrace 이벤트로 아래의 예제와 같이 DSHTTPService 컴포넌트에 대한 호출을 추적할 수 있습니다.

procedure TServerContainer1.DSHTTPService1Trace(Sender: TObject; AContext: TDSHTTPContext; ARequest: TDSHTTPRequest; AResponse: TDSHTTPResponse); begin LogInfo('HTTP Trace ' + AContext.ToString); LogInfo(' ' + ARequest.Document); LogInfo(' ' + AResponse.ResponseText); end;

HTTP 추적 정보는 클라이언트가 서버에 연결하기 위해 실제로 HTTP프로토콜을 사용했을 때만 볼 수

있다는 것에 알아둡시다. (디폴트인 TCP/IP 프로토콜을 사용하여 연결했을 때는 볼 수 없습니다)

아래는 추적 결과의 예입니다.

10Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

17:05:55.398 HTTP Trace TDSHTTPContextIndy 17:05:55.400 /datasnap/tunnel 17:05:55.403 OK

위 로그에서 AContext는 TDSHTTPContextIndy로, ARequest는 /datasnap/tunnel로, AResponse는 OK로

되어 있음을 알 수 있습니다.

2.1.1.1.5. TDSHTTPServiceAuthenticationManager

TDSHTTPServiceAuthenticationManager 컴포넌트는 HTTP 통신 프로토콜에 관한 인증 체크박스가

체크된 경우 Server 컨테이너에 추가되지만, 서버 컨테이너에 수동으로도 추가할 수도 있습니다.

TDSHTTPServiceAuthenticationManager 컴포넌트는 TDSHTTPService 컴포넌트의

AuthenticationManager 속성으로 연결됩니다.

TDSHTTPServiceAuthenticationManager 컴포넌트는 OnHTTPAuthenticate 이벤트 하나를 가지고 있는데,

DataSnap 클라이언트에서 서버로 제공되는 HTTP 인증 정보를 체크하기 위해서 사용할 수 있습니다.

procedure TServerContainer1.DSHTTPServiceAuthenticationManager1HTTPAuthenticate( Sender: TObject; const Protocol, Context, User, Password: string; var valid: Boolean); begin if (User = 'Bob') and (Password = 'Swart') then valid := True else valid := False end;

당연히, 이 인증 확인 코드는 샘플 코드일 뿐 제대로 된 것이 아니기 때문에, 예를 들면 데이터베이스에서

해쉬된 패스워드 버전을 조회하는 식으로 바꿔야 합니다. 클라이언트에서 서버로 유저 계정과 (해쉬된)

패스워드 정보를 보내지는 HTTP 인증에는 HTTPS를 사용하는 것이 최선의 방법이므로, 엠바카데로에서

현재 지원되는 HTTP와 TCP/IP 프로토콜에 더하여 HTTPS 프로토콜을 추가하기를 바라고 있습니다.

HTTPS는 보안 커넥션과 데이터 패킷의 암호화를 보장하며, 따라서 데이터 스니핑 툴을 사용하는 다른

누군가가 여러분의 유저 계정과 해쉬된 패스워드 정보를 알아내는 것이 불가능합니다. 여러분의 ISP 또는

웹마스터에게 문의하여 여러분의 도메인에 HTTPS가 가능한지 알아보시기를 강력하게 권합니다. (예를

들어 저는 https://www.bobswart.nl 주소를 사용합니다)

또 한가지 실제 운영을 할 DataSnap 서버 애플리케이션에서 사용을 권하는 좋은 테크닉은, HTTP 인증

시도를 로그 파일에 써넣는 것인데, 여기에 프로토콜과 컨텍스트 정보도 써넣을 수 있습니다. 이 방법으로

여러분은 누가 로그인 하고 있으며, 로그인을 시도하고 있는지 등을 알 수 있게 됩니다. (예를 들면

DataSnap 서버에 접근하려고 하는 사람이 가짜 로그인 시도를 하는 등을 알 수 있습니다.)

2.1.1.2. ServerMethodsUnitDemo

이제 ServerContainerUnitDemo.pas 유닛을 살펴봅시다. 이 유닛은 새 DataSnap 서버 애플리케이션의 또

다른 중요 유닛입니다. New DataSnap Server 다이얼로그에서 조상으로서 TDSServerModule 클래스를

지정하였으므로, TServerMethods1 타입은 TDSServerModule로부터 파생됩니다. (이것은

TDSServerModuleBase로부터 파생되었고, 이는 다시 TProviderDataModule로부터 파생되었으며,

Destroy 파괴자와 BeforeDestruction 프로시저가 추가되었습니다). TProviderDataModule 는 일반적인

TDataModule에서 파생되었으며, 프로바이더와 연동할 수 있는 기능이 추가되었습니다. (나중에 이에

대해 설명할 것입니다)

TServerMethods1의 조상 클래스 중 하나가 TDataModule이기 때문에, 디자인 탭은 데이터모듈에 대한

11Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

디자인 영역을 보여줍니다. 데이터 액세스 컨트롤 등의 넌비주얼 컴포넌트들을 배치할 수 있습니다.

3장에서는 데이터 액세스 컴포넌트를 배치할 것이지만, 지금은 디자인 영역을 비워두고 TServerMethods1

클래스에 메소드만 추가합니다.

만일 프로젝트 그룹에 추가적인 타겟으로 DataSnap 콘솔 애플리케이션이나 DataSnap 윈도우 서비스

애플리케이션을 추가하지 않을 것이라면, 서버 메소드의 구현을 착수하는 2.1.4 장으로 넘어가셔도 됩니다.

2.1.2. 멀티-타겟프로젝트 그룹 – 콘솔 애플리케이션

프로젝트 그룹으로 돌아와서, 이번에는 콘솔 애플리케이션으로 두 번째 타겟을 추가합니다: 프로젝트 그룹

노드에서 오른쪽 마우스를 클릭하여, “ Add New Project” 를 선택합니다. 오브젝트 리포지토리에서,

다시 DataSnap 서버 페이지로 가서 DataSnap 서버 아이콘을 더블 클릭합니다. 이번에는, New DataSnap

Server 다이얼로그에서 콘솔 애플리케이션을 선택합니다.

여기서 어떤 옵션들을 선택할지는 중요하지 않습니다. DataSnapServer 프로젝트의

ServerContainerUnitDemo.pas 및 ServerMethodsUnitDemo.pas 유닛을 재사용할 것이기 때문입니다.

OK를 클릭하여 새 프로젝트를 생성합니다. ServerContainerUnit2.pas 와 ServerMethodsUnit2.pas를

추가하여 다시 Project1.dproj를 작성합니다. 프로젝트 매니저에서 ServerMethodsUnit2.pas 유닛에서

오른쪽 마우스를 클릭하고 프로젝트에서 삭제합니다. 이 유닛에서 메소드 하나를 복사해야 하기 때문에

ServerContainerUnit2.pas를 당분간 보관합니다. 프로젝트를 DataSnapConsoleServer.dproj로

저장합니다.

ServerContainerUnitDemo.pas 와 새롭게 작성된 ServerContainerUnit2.pas (콘솔 애플리케이션용)의

내용을 비교해보면, RunDSServer라는 글로벌 프로시저가 포함되어 있다는 것을 볼 수 있을 것입니다. 이

전역 프로시저는 콘솔 애플리케이션에만 사용 가능하므로, DataSnapConsoleServer.dproj 프로젝트 소스

코드 안의 메인 블록의 begin 바로 앞에 프로시저를 복사하여 붙여 넣습니다.

12Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

코드 몇 부분에서 에러 인사이드(에러가 있는 부분을 표시해주는 붉은 색 밑줄) 표시가 나타날 것입니다.

DataSnapConsoleServer.dpr의 uses 절에 Windows 유닛을 추가하면 문제가 해결됩니다. 이제

DataSnapConsoleServer 는 아래와 같이 될 것입니다.

program DataSnapConsoleServer; {$APPTYPE CONSOLE} uses SysUtils, Windows, ServerContainerUnit2 in 'ServerContainerUnit2.pas' {ServerContainer2: TDataModule}; procedure RunDSServer; var LModule: TServerContainer2; LInputRecord: TInputRecord; LEvent: DWord; LHandle: THandle; begin Writeln(Format('Starting %s', [TServerContainer2.ClassName])); LModule := TServerContainer2.Create(nil); try LModule.DSServer1.Start; try Writeln('Press ESC to stop the server'); LHandle := GetStdHandle(STD_INPUT_HANDLE); while True do begin Win32Check(ReadConsoleInput(LHandle, LInputRecord, 1, LEvent)); if (LInputRecord.EventType = KEY_EVENT) and LInputRecord.Event.KeyEvent.bKeyDown and (LInputRecord.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE) then break; end; finally LModule.DSServer1.Stop; end ; finally LModule.Free; end; end; begin try RunDSServer; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end end.

아직 간단한 3 가지 작업을 더 해야 합니다. DataSnapConsoleServer 프로젝트가 아직

ServerContainerUnit2.pas를 uses 하고 있으므로, 지금 이 유닛을 삭제하겠습니다. 프로젝트 매니저에서

소스 위에서 오른쪽 마우스를 클릭하고 “ Remove From Project” 를 선택합니다. 다음으로

DataSnapConsoleServer.exe 노드에서 오른쪽 마우스를 클릭하여, “ Add” 를 선택하고

ServerContainerUnitDemo.pas 와 ServerMethodsUnitDemo.pas을 선택하여 프로젝트에 추가합니다.

그 결과, TServerContainer2를 참조하는 모든 곳에서 문법 에러로 표시될 것입니다.

ServerMethodsUnitDemo.pas는 TServerContainer1 타입을 선언해야 하며, 따라서 이 마지막 문제를

13Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

해결하기 위해서 DataSnapConsoleServer의 소스 코드에서 TServerContainer2를 TServerContainer1로

이름을 변경해야 합니다. (전체적으로 3곳 수정)

이제 원래의 DataSnapServer.dproj 프로젝트뿐만 아니라 새로운 DataSnapConsoleServer.dproj

프로젝트도 컴파일할 수 있게 되었습니다. 두 프로젝트에서 서로 ServerMethodsUnitDemo.pas 유닛과

ServerContainerUnitDemo.pas 를 공유합니다.

2.1.3. 멀티 타겟 프로젝트 그룹 – 윈도우 서비스

이제 DataSnap VCL 폼 서버와 DataSnap 콘솔 서버 프로젝트를 한 프로젝트 그룹에 포함시켰으니, 이제

DataSnap 윈도우 서비스 애플리케이션 하나가 남았습니다. 이 타겟을 추가하기 위해서, 프로젝트

그룹에서 오른쪽 마우스를 클릭하여 “ Add New Project” 을 선택한 후, 오브젝트 리포지토리에서 New

DataSnap Server 아이콘을 다시 더블 클릭합니다. 이번에는 서비스 애플리케이션을 선택하고 통신

프로토콜 옵션 (TCP/IP, HTTP, HTTP 인증) 또한 선택합니다. 곧 살펴보겠지만, 서비스 애플리케이션에

대한 서버 컨테이너는 VCL Forms 나 콘솔 애플리케이션 측 서버 컨테이너와는 조금 다릅니다. 그래서

여기 있는 모든 프로토콜 옵션을 선택하여야 합니다.

New DataSnap Server 다이얼로그의 결과로 ServerContainerUnit과 ServerMethodsUnit이 추가된 새로운

프로젝트가 생성됩니다. ServerMethodsUnit은 전에 본 것과 동일하므로 새 프로젝트에서 삭제하고 VCL

Forms와 콘솔 DataSnap 애플리케이션에서 공통으로 사용하고 있는 ServerMethodsUnitDemo.pas로

대체합니다.

반면, 새로운 유닛 ServerCotainerUnit1.pas는 다릅니다. TDSServer, TDSServerClass 와 트랜스포트

컴포넌트를 포함하는 데에 TDataModule를 사용하지 않고, TService로부터 파생되는 새로운 클래스에서

DataSnap 컴포넌트들을 포함합니다. 또한 TService로부터 파생되는 것과는 별도로 서비스의 Stop,

Pause, Continue 와 Interrogate 이벤트를 구현하기 위한 4 개의 특별한 메소드가 추가되어 있습니다.

type TServerContainer3 = class(TService) DSServer1: TDSServer; DSTCPServerTransport1: TDSTCPServerTransport; DSHTTPService1: TDSHTTPService; DSHTTPServiceAuthenticationManager1: TDSHTTPServiceAuthenticationManager; DSServerClass1: TDSServerClass; procedure DSServerClass1GetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); procedure ServiceStart(Sender: TService; var Started: Boolean); private { Private declarations } protected function DoStop: Boolean; override; function DoPause: Boolean; override; function override; DoContinue: Boolean; procedure DoInterrogate; override; public function GetServiceController: TServiceController; override; end;

바꾸어 말하면, 윈도우 서비스 프로젝트에서는 원래의 유닛 ServerContainerUnitDemo.pas를 공유할 수

없습니다. ServerContainerUnit1.pas를 ServerContainerUnitServiceDemo.pas로 이름 바꾸어야 합니다.

다음으로, 프로젝트 자체를 DataSnapServiceServer.dproj로 저장합니다.

ServerContainerUnitServiceDemo에서 예전의 유닛 ServerMethodsUnit2.pas를 참조부분을 찾아

ServerMethodsUnitDemo.pas로 수정해야 합니다. 그래서 3 개의 타겟 모두에서 같은 서버 메소드를

사용하게 됩니다.

14Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

2.1.4. 서버 메소드

일단 ServerMethodsUnitDemo 유닛이 포함된 DataSnap 서버 프로젝트가 준비되었다면, 이제 서버

메소드에 대해 좀 더 자세히 알아보기로 합시다.

앞에서 언급한 것처럼, TServerMethod1 클래스는 RTTI를 이용하여 DataSnap 클라이언트에게

메소드들을 노출하는 DataSnap 서버 객체입니다. 여러분이 “ Include sample methods” 옵션을

체크하였다면 클래스에 샘플 메소드인 EchoString 함수가 추가되었을 것입니다. 이제 다른 함수로서

DataSnap 서버 컴퓨터로부터 현재 시간을 반환하는 함수를 추가해봅시다. 그러기 위해, 다음과 같이

수정하여 TServerMethods1의 정의 부분에 2개의 퍼블릭 메소드를 추가합니다.

type TServerMethods1 = class(TDSServerModule) private { Private declarations } public { Public declarations } function EchoString(Value: string): string; function ServerTime: TDateTime; end;

ServerTime 메소드의 구현은 예제로 제공된 EchoString 메소드만큼이나 매우 간단합니다.

function TServerMethods1.EchoString(Value: string): string; begin Result := Value; end; function TServerMethods1.ServerTime: TDateTime; begin Result := Now; end;

이제 이 서버 애플리케이션을 컴파일하고 실행합니다. 여러 프로젝트 타겟으로 구성했다면 바로

테스트하기 가장 편리한 것은 DataSnapServer 실행파일입니다. 윈도우 버전과 보안 설정 수준 에 따라

DataSnapServer 애플리케이션의 일부 기능을 막고 있다는 것을 알려주는 윈도우 보안 경고를 보게 될

수도 있습니다.

이것은 DataSnapServer 애플리케이션이 TCP/IP와 HTTP로 요청을 리스닝하고 있기 때문입니다. “ Allow

access” 버튼을 클릭하여 액세스를 허용하도록 하고, 이제 DataSnap 서버가 제대로 실행됩니다.

15Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

2.2. DataSnap 클라이언트

첫 번째 DataSnap 서버가 실행되어 들어오는 요청을 리스닝하는 상태가 되었으니, 이제 클라이언트를

작성할 때가 되었습니다. 이 장에서는, 어떻게 클라이언트에서 서버로 연결할 수 있는지, 어떻게 서버

클래스를 생성하여 메소드를 임포트할 수 있는지를 설명하겠습니다.

DataSnap 서버가 실행되고 있으므로 DataSnap 클라이언트 애플리케이션 프로젝트를 작성 할 수

있습니다. 디자인타임에 DataSnap 서버 프로젝트와 DataSnap 클라이언트 프로젝트를 쉽게 스위치 하기

위해, DataSnap 클라이언트 프로젝트를 같은 프로젝트 그룹에 추가합니다. 어떠한 프로젝트도 DataSnap

클라이언트가 될 수 있지만, 이번 데모에서는 VCL Forms Application을 선택하여 프로젝트를 생성하고

메인 폼을 ClientForm.pas로, 프로젝트를 DataSnapClient.dpr로 저장합니다.

툴 팔레트의 DataSnap Server 페이지에는 6 개의 DataSnap 서버 컴포넌트들이 있지만, DataSnap Client

페이지에는 우리가 지금 사용할 컴포넌트들이 포함되어 있지 않습니다.

DataSnap Client 페이지에 있는 컴포넌트들은 "예전의" DataSnap

컴포넌트들로서, 지금도 사용할 수는 있으나 이제는 DataSnap을

사용하는 데 있어 추천할 만한 방법은 아닙니다.

여기에는 한 가지 예외가 있습니다. DataSnap 2010에서 새로 추가된

TDSProviderConnection 컴포넌트는 "이전의" DataSnap 서버를 새로운

DataSnap 클라이언트와 연결하기 위해서 사용할 수 있습니다.

(3.2장에서 보여드릴 것입니다)

DataSnap Client 페이지 대신, 우리는 dbExpress 페이지에서 TSqlServerMethod라는 새로운 컴포넌트를

찾아보아야 합니다. (아래 그림에서 보면 기존의 다른 dbExpress 컴포넌트들은 TSQL로 시작하지만

TSqlServerMethod는 유일하게 TSql로 시작하기 때문에 금방 알아볼 수 있을 것입니다)

TSqlServerMethod 컴포넌트는 DataSnap 서버에 있는 원격의 메소드를

호출하기 위하여 사용되지만, 먼저 DataSnap 서버가 연결될 필요가

있습니다.

서버와의 연결에는 예전의 TxxxConnection 컴포넌트들이 아닌

TSQLConnection 컴포넌트를 사용됩니다. 이렇게 하기 위해,

TSQLConnection 컴포넌트의 Driver 속성의 드롭다운 목록에

DataSnap이라는 새로운 드라이버 이름을 선택할 수 있습니다.

따라서, TSQLConnection 컴포넌트를 ClientForm 위에 놓고, Driver

속성을 DataSnap으로 지정합니다. 그 결과로, 오브젝트 인스펙터에서

Driver 속성의 이름 왼편에 플러스 기호가 표시되며 속성을 펼쳐서 모든

하위 속성들을 볼 수 있습니다.

16Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

CommunicationProtocol 속성은 기본적으로 비어 있으며, TSQLConnection은 이 상태에서는 프로토콜로

TCP/IP를 사용할 것입니다 (지정된 포트 211를 통해 통신).

서버 측과 똑같이 BufferKBSize은 디폴트값인 32 (KB)로, Port 는 디폴트값인 211로 지정되어 있습니다.

실제 상황에서는, 포트 211은 DataSnap 서버와 연결하는 포트로 잘 알려져 있으므로, 저는 항상 포트

번호를 211에서 다른 값으로 변경합니다 (서버 측과 클라이언트 측 양쪽 모두)

HostName, UserName과 Password는 DataSnap 서버와 연결하기 위해서 사용됩니다. 로컬 환경에서의

테스트를 위해서는 HostName을 localhost로 지정할 수 있으나, 일반적으로 이 속성의 값으로 특정 호스트

이름, DNS 이름 또는 직접 IP 번호를 지정할 수 있습니다.

연결 과정에서 로그인 다이얼로그가 나타나는 것을 막기 위해서는 TSQLConnection 컴포넌트의

LoginPrompt 속성을 False로 지정해야 한다는 것을 잊지 마십시오.

TSQLConnection의 Driver 속성이 지정되고 나면 Connected 속성을 True로 설정하여 DataSnap 서버와

연결할 수 있습니다. 서버 측에 연결하기 위해서는 DataSnap 서버가 반드시 실행되고 있어야 한다는 것에

주의 하십시오.

2.2.1. DataSnap 클라이언트 클래스들

서버와의 연결이 된 후에는, TSQLConnection 컴포넌트 위에서 오른쪽 마우스를 클릭하고 “ Generate

17Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

DataSnap client classes” 메뉴를 선택하면, TServerMethods1Client 라 불리는 클래스를 가진

Unit1이라는 이름의 새 유닛을 생성됩니다 (서버 측의 DataSnap 서버 메소드 클래스의 실제 이름에

“ Client” 부분이 덧붙여진 이름입니다). 이 유닛을 ServerMethodsClient.pas라는 이름으로 저장합니다.

생성된 TServerMethods1Client 클래스의 정의 부분은 아래와 같을 것입니다;

type TServerMethods1Client = class private FDBXConnection: TDBXConnection; FInstanceOwner: Boolean; FEchoStringCommand: TDBXCommand; FServerTimeCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection); overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function EchoString(Value: string): string; function ServerTime: TDateTime; end;

보이는 것처럼, TServerMethods1Client 클래스에 대한 2 개의 생성자와 1 개의 파괴자가 있으며, 우리가

DataSnap 서버 쪽에서 정의했던 2 개의 서버 메소드가 있을 것입니다.

이 메소드들을 사용하기 위해서, ServerMethodsClient 유닛을 ClientForm의 uses 절에 추가하고, TButton

컴포넌트를 클라이언트 폼 위에 배치하고 그 OnClick 이벤트 핸들러에서 다음과 같이 코드를 작성합니다:

procedure TForm2.Button1Click(Sender: TObject); var Server: TServerMethods1Client; begin Server := TServerMethods1Client.Create(SQLConnection1.DBXConnection); try ShowMessage(DateTimeToStr(Server.ServerTime)); finally Server.Free; end;

end;

이 코드는 TServerMethods1Client의 인스턴스를 생성하고, ServerTime 서버 메소드를 호출하고,

마지막으로 DataSnap 서버로의 프록시 메소드를 해제합니다.

컴파일하고 실행한 후 이 버튼을 클릭하면, 예상대로 현재 서버 시간을 표시하는 메시지박스가 나타날

것입니다.

비슷한 방법으로 여러분이 직접 EchoString 메소드를 가지고 연습해보시기 바랍니다.

18Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

2.2.1.1. HTTP 통신 프로토콜

TSQLConnection 컴포넌트의 CommunicationProtocol 속성의 디폴트 값이 TCP/IP 라고 언급했었습니다.

따라서 우리는 HTTP 추적 메시지를 전혀 볼 수 없습니다 (2.1.1.1.4장에서 정의했었습니다). 그러나 통신

프로토콜을 변경하는 것은 어려운 일이 아닙니다. TSQLConnection의 Driver 속성의 하위 속성인

CommunicationProtocol의 값으로 HTTP를 지정하기만 하면 됩니다. 211 값은 TCP/IP용으로 사용되므로

Port 속성 또한 변경해야 할 것입니다. ServerContainer에서 TDSHTTPService 컴포넌트에서 지정한 포트

값과 동일한 값을 지정해야 한다는 것을 잊지 마십시오.

이렇게 수정한 후에 DataSnap 클라이언트를 다시 실행하면, 다음과 같은 애플리케이션 에러가 발생할

것입니다:

이 에러를 해결하려면 DSHTTPLayer 유닛을 DataSnap 클라이언트(예를 들어 ClientForm)의 uses 절에

추가하면 됩니다.

2.2.1.2. HTTP 인증

HTTP 통신 프로토콜을 사용했을 때의 장점 중 하나는 HTTP 인증 기능을 추가할 수 있다는 것입니다. 이

것은 2.1.1.1.5장에서 언급한 것처럼 DataSnap 서버 측의 TDSHTTPServiceAuthenticationManager

컴포넌트에 의해서 지원됩니다.

OnHTTPAuthenticate 이벤트 핸들러를 구현되면 거기서 HTTP 인증에 관한 체크가 이루어지며,

TDSHTTPServiceAuthenticationManager에서 액세스를 허용하도록 올바른 정보를 전달해야 합니다.

그렇지 않으면 “ HTTP/1.1 401 Unauthorized error” 라는 에러가 발생하게 됩니다.

DataSnap 클라이언트에서 DataSnap 서버, 더 정확하게는 TDSHTTPServiceAuthentication 컴포넌트로

HTTP 인증 유저이름과 패스워드 정보를 전달하려면, 클라이언트 폼 위에 있는 TSQLConnection

컴포넌트의 DSAuthUser와 DSAuthPassword 속성의 값을 지정해야 합니다.

19Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

DataSnap 서버를 로컬 컴퓨터에서 테스트하는 경우가 아니라면 HostName에도 값을 지정해야 합니다.

2.3. DataSnap 서버 배포

서버와 클라이언트 모두 같은 로컬 컴퓨터에서 실행되고 있다면 위 예제는 잘 동작합니다. 그러나 실제

상황에서는, DataSnap 서버는 서버 컴퓨터에서 실행될 것이고, 하나 이상의 클라이언트가 네트워크를

통해 이 서버 컴퓨터로 연결할 것입니다. DataSnap 서버 애플리케이션이 실행되는 컴퓨터는 일반적으로

델파이가 설치되지 않은 컴퓨터일 것입니다. 이것은 DataSnap 서버를 런타임 패키지 없이 컴파일할 것을

고려해야 한다는 것을 의미하므로, 이런 경우 단일의 큰 실행 파일을 만들게 됩니다.

지금까지는 데이터 액세스 컴포넌트를 사용하지 않았으므로, 추가로 데이터베이스 드라이버나 외부

DLL이 필요하지 않습니다.

2.3.1. DataSnap 클라이언트 배포

DataSnap 클라이언트 애플리케이션이 DataSnap 서버 애플리케이션과 다른 컴퓨터에서 실행되고 있다면,

클라이언트가 서버에 연결될 수 있도록 주의해야 합니다. 그러기 위해, 클라이언트 폼의 TSQLConnection

컴포넌트가 Driver 속성의 하위 속성인 CommunicationProtocol과 Port 값뿐만 아니라 HostName 속성

값도 지정해야 합니다. 가능하면 IP 주소를 지정하는 대신 DNS 이름을 사용하도록 하십시오. 제가

DataSnap 서버를 만드는 경우를 예로 들자면, HostName으로 www.bobswart.nl 주소를 사용할 것입니다.

(프로토콜은 CommunicationProtocol 속성에서 지정하므로 접두어 http:// 를 지정하지 않아야 합니다)

20Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

3. DataSnap과 데이터베이스

간단한 서버 메소드를 작성을 위해 델파이 2010 DataSnap 프레임워크를 이용하는 것과 별개로, 서버에

데이터베이스 액세스 기능을 추가하여 멀티티어 데이터베이스 애플리케이션으로 아키텍처를 변경할 수

있는데, 이러한 경우 DataSnap 서버가 데이터베이스에 연결하고 DataSnap 클라이언트는 데이터베이스

드라이버 없이 씬 클라이언트 혹은 스마트 클라이언트가 됩니다.

지금까지 작성해온 DataSnap 예제에서는 SQLConnection 컴포넌트와 그로부터 생성된 클라이언트

클래스만 사용했었습니다만, 이제부터는 새로운 DataSnap 컴포넌트인 TSqlServerMethod와

TDSProviderConnection를 사용해볼 것입니다.

먼저, 서버에서 클라이언트로 TDataSet을 노출해야 하므로, ServerMethodsUnitDemo로 가서 데이터모듈

위에 TSQLConnection 컴포넌트를 내려놓습니다. TSQLConnection 컴포넌트를 여러분이 원하는

DBMS과 테이블에 연결합니다. (예제에서는 BlackfishSQL의 Employees 예제 데이터베이스에 있는

Employee 테이블로 연결하겠습니다)

이렇게 하기 위해, ServerMethods1의 디자인 영역에 TSQLConnection 컴포넌트를 배치합니다.

(ServerMethodsUnitDemo.pas 유닛). TSQLConnection 컴포넌트의 Driver 속성을 BlackfishSQL로

지정하고, Driver 속성을 열어서 그 하위의 Database 속성에 employee.jds의 경로를 지정합니다.

(Windows XP의 경우 C:\Documents and Settings\All Users\Documents\RAD Studio\7.0\Demos \database\databases\BlackfishSQL 경로에, Windows Vista / Windows 7의

경우 C:\Users\Public\Documents\RAD Studio\7.0\Demos\database\databases \BlackfishSQL 경로에 있습니다)

TSQLConnection 컴포넌트의 LoginPrompt 속성을 False로 지정하고, Employee.jds 데이터베이스와의

연결을 할 수 있는지 확인하기 위해 Connected 속성을 True로 지정해봅니다.

다음으로, SQLDataSet 컴포넌트를 TSQLConnection 컴포넌트 옆에 내려놓고, SQLConnection 속성을

TSQLConnection 컴포넌트로 지정합니다.

CommandType을 ctQuery 그대로 두고, SQL 쿼리를 입력하기 위해서 CommandText 속성을 더블

클릭합니다.

21Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

아래와 같이 SQL문을 입력하고 OK를 클릭하여 다이얼로그를 닫습니다.

SELECT EMP_NO, FIRST_NAME, LAST_NAME, HIRE_DATE, JOB_COUNTRY FROM EMPLOYEE

TSQLConnection 컴포넌트의 LoginPrompt와 Connected 속성을 False로 하고, TSQLDataSet 의 Active

속성 또한 False로 지정해야 합니다.

이제 TSQLDataSet 컴포넌트의 내용을 받아오기 위해서 ServerMethodsUnitDemo 유닛의

TServerMethods1 클래스에 퍼블릭 함수를 추가해야 합니다.

type TServerMethods1 = class(TDSServerModule) SQLConnection1: TSQLConnection; SQLDataSet1: TSQLDataSet; private { Private declarations } public { Public declarations } function EchoString(Value: string): string; function ServerTime: TDateTime; function GetEmployees: TDataSet; end;

TServerMethod1 정의부분에서 보이는 것처럼, GetEmployees 라는 새로운 함수를 다음과 같이

구현합니다.

22Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

function TServerMethods1.GetEmployees: TDataSet; begin SQLDataSet1.Open; // 데이터를 가져올 수 있도록 합니다 Result := SQLDataSet1 end;

서버를 재컴파일하고 다시 실행시킵니다. 만약 DataSnap 서버를 닫았는데도 컴파일이 안 된다면,

DataSnap 서버가 여전히 실행되고 있을 가능성이 높습니다.

3.1. TSqlServerMethod

다시 DataSnap 클라이언트 애플리케이션으로 돌아옵니다. TSQLConnection 컴포넌트는 더 이상

DataSnap 서버와 연결되어 있지 않을 것입니다. (만일 여전히 연결되어있다면, DataSnap 프로세스가

여전히 실행 중이기 때문에 서버를 재컴파일할 수 없을 것입니다). 서버의 정보를 다시 가져오기 위해서

Connected 속성을 다시 True로 설정하고 오른쪽 마우스 버튼을 다시 사용하여 클라이언트 클래스를 다시

생성합니다.

이전 ServerMethodsClient 유닛을 덮어쓰기 위해, 프로젝트에서 이전 버전의 ServerMethodsClient를

삭제하고 “ Generate DataSnap client classes” 메뉴를 다시 선택합니다. 새롭게 작성된 유닛을 다시

ServerMethodsClient.pas로 저장하게 되면, 이전 클라이언트 코드는 수정하지 않아도 됩니다.

“ Generate DataSnap client classes” 메뉴를 다시 실행하고 나면, 생성된 TServerMethods1Client

클래스에는 GetEmployees 메소드가 추가되어 있을 것입니다. (ServerTime와 EchoString 함수도 역시

나타납니다)

type TServerMethods1Client = class private FDBXConnection: TDBXConnection; FInstanceOwner: Boolean; FEchoStringCommand: TDBXCommand; FServerTimeCommand: TDBXCommand; FGetEmployeesCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection); overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function EchoString(Value: string): string; function ServerTime: TDateTime; function GetEmployees: TDataSet; end;

GetEmployees 메소드에서 TDataSet 데이터를 가져오기 위해 툴 팔레트의 dbExpress 페이지에 있는

TSqlServerMethod 컴포넌트를 사용할 수 있습니다. 클라이언트 폼 위에 TSqlServerMethod 컴포넌트를

내려놓고, SQLConnection 속성을 SQLConnection1로 연결하고, ServerMethodName 드롭다운 리스트를

열어서 호출할 수 있는 모든 메소드들을 나열해봅니다.

여러 DSAdmin 메소드들 (DSServer 컴포넌트의 HideDSAdmin 속성을 True로 설정하면 나타나지 않게 할

수 있습니다), 3개의 DSMetadata 메소드들, 7개의 TServerMethods.AS_xxx 메소드들 (본래의 IAppServer

인터페이스를 제공), 그리고 마지막으로 우리가 만든 TServerMethods1의 EchoString, ServerTime,

GetEmployees 메소드들이 있습니다.

현재의 예제에서는 ServerMethodName 속성의 값으로 TServerMethods1.GetEmployees를 선택해야

합니다. ServerMethodName의 값을 이렇게 설정함으로써 SqlServerMethod의 결과는 employees의

레코드들을 포함하는 데이터셋이 됩니다. (혹은 우리가 작성한 SQL 문장의 결과를 갖게 됩니다)

23Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

통상적인 방식대로 TDataSetProvider, TClientDataSet와 TDataSource 연결을 사용하여 TDBGrid에

데이터를 보여줄 수 있습니다.

클라이언트 폼 위에 TDataSetProvider을 내려놓고 DataSet 속성을 SqlServerMethod 컴포넌트로 연결한

다음, TClientDataSet 컴포넌트를 내려 놓고 ProviderName 속성을 DataSetProvider 컴포넌트로

연결합니다. RemoteServer 속성은 그냥 비워두는데, 이것은 “ 이전의” DataSnap 방식에서만

사용되었으며 새로운 DataSnap 구조에서는 더 이상 사용되지 않습니다.

마지막으로, 클라이언트 폼 위에 TDataSource를 내려 놓고 DataSet 속성을 TClientDataSet 컴포넌트로

연결하고 나면, 이제 TDBGrid와 TDBNavigator 컴포넌트를 사용할 수 있게 됩니다. 두 컴포넌트의

DataSource 속성을 TDataSource 컴포넌트로 연결하여 화면에서 데이터를 보여줍니다.

디자인 시점에서 연결을 확인하기 위해서 ClientDataSet의 Active 속성을 True로 지정해볼 수 있습니다.

이렇게 하면 SqlServerMethod의 Active 속성 값이 토글될 것입니다 (데이터를 가져오는 동안 잠깐 True로

하고 그 후에 다시 False로 합니다), 이렇게 하면 DataSnap 클라이언트와 서버 사이의 연결이 되는

과정에서 TSQLConnection 컴포넌트의 Connected 속성을 True로 바뀔 것입니다.

어쨌든 연결이 활성화 되어 있다면, 그 결과로 TClientDataSet과 TSQLConnection가 활성화되고

TDBGrid에 데이터가 표시됩니다.

이것은 데이터를 읽기 전용으로 보기 위한 쉬운 방법입니다. 지금 제가 “ 읽기 전용” 이라고 언급 한 것은,

TSqlServerMethod는 이런 방식으로 TDataSetProvider-TClientDataSet 조합이 DataSnap

클라이언트로부터 DataSnap 서버로 업데이트를 보내는 것을 허용하지 않기 때문입니다.

TSqlServerMethod는 읽기전용 데이터를 연결하는 가볍고 편리한 방법입니다. 이것은 DataSnap

서버로부터 사용자들이 수정할 수 없어야 하는 데이터를 보여줘야 하는 경우, TServerMethods1

클래스로부터 TSQLDataSet 결과를 보여주는 이 방식이 아주 좋은 방법이라는 것을 의미합니다.

그러나, 업데이트를 허용해야 할 필요가 있을 경우에는 데이터를 표시하기 위해 다른 접근방식을 사용해야

합니다.

24Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

3.2. TDSProviderConnection

업데이트를 적용하려는 경우라면, 서버 측의 DataSetProvider를 참조 할 수 있게 해주는

TDSProviderConnection 컴포넌트가 필요합니다. 이 방법을 사용하면 데이터를 읽기뿐만 아니라

업데이트도 가능하게 됩니다.

먼저, 서버 측의 서버 데이터모듈을 수정할 필요가 있습니다. 지금까지는 TDataSet의 결과를 리턴하는

함수만을 추가했기 때문에, TDataSetProvider를 추가해야 하고 DataSnap 서버로부터 DataSnap

클라이언트로 나타나게 해야 합니다. 따라서 ServerMethodsUnitDemo 유닛으로 돌아와서 TSQLDataSet

옆에 TDataSetProvider 컴포넌트를 내려놓고, TDataSetProvider의 DataSet 속성을 TSQLDataSet로

연결합니다. TDataSetProvider 컴포넌트의 이름을 변경하여 dspEmployees처럼 의미가 있는 이름으로

변경합니다.

이제 DataSnap 서버를 재컴파일하고 실행합니다. 이제 표시되는 데이터를 수정하기 위해 클라이언트를

수정할 수 있습니다.

3.2.1. TDSProviderConnection 클라이언트

TDataSetProvider 컴포넌트를 사용하기 위한 DataSnap 클라이언트를 수정하기 위해서, 클라이언트 폼

위의 TSqlServerMethod와 TDataSetProvider 컴포넌트를 삭제하고 그 대신 TDSProviderConnection

컴포넌트를 추가합니다.

SQLConnection 속성을 TSQLConnection 컴포넌트로 연결하여 DataSnap 서버와 연결합니다. 또한

ProviderConnection의 ServerClassName 속성의 값을 지정해야 합니다. 약간 불편하게도 드롭다운

목록으로 선택 가능한 값들이 나타나지 않습니다. 바로 지금, TDSServerModule의 이름 값을 직접

지정해야 합니다. 우리 예제의 경우에는 TServerMethods1 입니다.

이전 예제에서, TClientDataSet 는 ProviderName 속성을 DataSetProvider1으로만 연결했었습니다.

TDSProviderConnection 컴포넌트를 사용하는 경우에는 먼저 TClientDataSet의 RemoteServer 속성을

TDSProviderConnection 컴포넌트로 지정해야 하며, 다음으로 ProviderName 속성에 대한 새로운 값을

선택합니다. (현재 DataSetProvider1 값으로 지정되어 있는데, 이제 dsEmployees로 연결해야만 합니다.

dsEmployees는 DataSnap 서버에서 노출된 TDataSetProvider 컴포넌트를 의미 있게 지정한 이름입니다)

ProviderName 속성의 드롭다운 리스트에 dspEmployees가 나타날 것입니다. (ServerDataMod 유닛에서

노출된 TDataSetProvider 컴포넌트의 이름)

디자인 시점에 데이터를 조회하기 위해서 TClientDataSet 컴포넌트의 Active 속성을 다시 True로

설정합니다.

25Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

TClientDataSet 컴포넌트의 Active 속성을 True로 설정하면 TSQLConnection 컴포넌트의 Connected

속성도 True로 설정됩니다. 여기서 주의할 것 한가지는, 디자인 시에 클라이언트 폼에서 이 두 가지 속성을

True로 두는 것은 좋은 방법이 아니라는 것입니다. 무엇보다 먼저, 델파이 개발환경에서 DataSnap

클라이언트 프로젝트를 오픈할 때마다 DataSnap 서버로 연결을 시도할 것이며, 그때 서버가 실행되고

있지 않다면 에러가 날 것입니다. 그 다음으로, 실행 시에 애플리케이션을 시작할 때 연결이 가능한 상태가

아니라면, 애플리케이션에서 예외가 발생하면서 제대로 시작되지 않을 것입니다. 이렇게 되면 로컬

데이터로 애플리케이션을 사용할 수도 없게 됩니다.

더 좋은 방법은 TSQLConnection 컴포넌트와 TClientDataSet를 명시적으로 활성화하기 위한 메뉴나

버튼을 이용해 처리하는 것입니다. 이 동작은 사용자 이름과 패스워드 정보를 전달하기 위한 좋은

지점이기도 합니다(뒤에서 다룰 것입니다). 일단은, TClientDataSet의 Active 속성과 TSQLConnection

컴포넌트의 Connected 속성을 False로 설정합니다. 다음으로 클라이언트 폼에 새 버튼을 놓고 그

OnClick 이벤트 핸들러에서 명시적으로 TClientDataSet를 오픈합니다.

procedure TForm2.Button2Click(Sender: TObject); begin ClientDataSet1.Open; end;

이제 클라이언트 측에서 데이터를 수정하고 서버로 다시 보내는 코드를 작업을 해보겠습니다.

3.2.2 데이터베이스 업데이트

애플리케이션에서 클라이언트의 데이터 수정 내용을 서버에 다시 보내기 위한 방법에는 자동으로

처리하는 방법과 수동으로 처리하는 방법 두 가지가 있습니다. 두 가지 방법 모두 결국은 같은 메소드를

호출하지만, 호출하는 방식이 자동으로 처리되는지 사용자의 명시적인 명령으로 호출하는지의 차이이며,

각각 장단점이 있습니다.

자동 처리 방식에 대해서는, TClientDataSet의 OnAfterInsert, OnAfterPost와 OnAfterDelete 이벤트를

이용할 수 있는데, 이 이벤트들은 데이터에 변경이 생겼을 때 발생하기 때문입니다. 이벤트 핸들러(단일

이벤트 핸들러를 공유할 수도 있습니다) 안에서 TClientDataSet의 ApplyUpdates 메소드를 호출하여

데이터 변경 내용("델타"라고 부릅니다)을 서버로 다시 보내게 됩니다.

26Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

procedure TForm2.ClientDataSet1AfterPost(DataSet: TDataSet); begin ClientDataSet1.ApplyUpdates(0); end;

업데이트 동안 어떤 일이 발생한다면(레코드가 없어지는 등), TClientDataSet의 OnReconcileError

이벤트에서 피드백 정보를 알아낼 수 있으며, 이에 대해서는 3.2.3장에서 더 자세히 다룰 것입니다.

DataSnap 서버로 업데이트 내용을 수동으로 보내는 방법에서도 역시 TClientDataSet의 ApplyUpdates

메소드를 사용하지만, 이 경우에는 메소드가 OnAfterInsert, OnAfterPost와 OnAfterDelete 이벤트

핸들러에서 호출하지 않습니다. 대신에, 클라이언트 폼에 버튼을 추가하여 사용자가 명시적으로 서버에

업데이트 내용을 보내도록 합니다.

procedure TForm2.btnUpdateClick(Sender: TObject); begin ClientDataSet1.ApplyUpdates(0); end;

ApplyUpdates를 자동으로 호출하는 방식의 장점은 사용자가 서버로 수정 내용을 다시 보내는 것을 결코

잊지 않는다는 것입니다. 그러나 단점은 취소(undo)가 안 된다는 것입니다. 일단 데이터를 변경하면

데이터 변경은 자동으로 서버로 적용됩니다. 이에 반해서, 수동 방식을 사용하는 경우 모든 변경 사항이

클라이언트 측의 TClientDataSet 컴포넌트의 메모리 안에 유지됩니다. 이 방법은 시용자가 수정의 특정

부분(마지막 수정이나 특정 레코드, 또는 대기중인 전체 수정 내용 등)을 취소할 수 있도록 허용합니다.

사용자가 준비되었을 때 “ 수정” 버튼을 클릭하여 ApplyUpdates 메소드를 호출합니다. 이 경우에

잠재적인 위험성은, 사용자가 수정 버튼 클릭하는 것을 잊을 수도 있다는 점입니다. 그래서

TClientDataSet에 수정된 내용이 아직 남아있는 경우 화면을 닫는 것을 방지하기 위해 화면이나

애플리케이션에서 확인하는 절차가 필요합니다. 이럴 때는 TClientDataSet의 ChangeCount 속성을

검사하여 확인할 수 있습니다.

3.2.3. 업데이트 에러 조정(Reconcile)

TClientDataSet 컴포넌트의 ApplyUpdates 메소드에는 업데이트 적용을 중단하기 전에 허용되는 에러의

최대 수를 가리키는 하나의 인자 MaxErrors가 있습니다.

DataSnap 서버에 두 개의 클라이언트가 연결되고 각각 Employees 데이터를 얻어온 후, 둘 다 첫

레코드를 수정한다면 어떻게 될까요. 지금까지 구축한 내용에 따라, 두 클라이언트 모두 TClientDataSet

컴포넌트의 ApplyUpdates 메소드를 사용하여 업데이트된 레코드를 다시 DataSnap 서버로 보낼 것입니다.

양쪽 모두 ApplyUpdates의 인자 MaxErrors에 대한 값으로 0를 넘긴다면, 두 번째 업데이트 시도는 중단될

것입니다. 두 번째 클라이언트는 업데이트가 중단되기 전 허용되는 에러/충돌의 수를 0보다 큰 숫자

값으로 지정하여 넘길 수도 있고, 아무리 많은 에러가 발생하더라도 수정 작업을 계속하도록 지시하는 -1

값을 넘길 수도 있습니다. 그러나, 어떻게 하더라도 앞의 클라이언트에 의해 변경된 레코드는 결코

업데이트 되지 않습니다. 다시 말해, 이미 업데이트된 레코드와 필드에 대한 업데이트를 처리하기

위해서는 조정(reconcile) 액션을 수행하여야 합니다.

다행히, 델파이는 이러한 목적을 위해 특별히 준비된 매우 유용한 다이얼로그를 가지고 있습니다. 에러

조정이 필요할 때마다, DataSnap 클라이언트 애플리케이션에 이 다이얼로그 추가를 고려해야 합니다.

(혹은 직접 만들 수도 있습니다만, 어쨌든 적어도 비슷한 작업을 처리할 수 있어야 합니다)

델파이의 기본 다이얼로그를 사용하려면, 메뉴에서 File | New – Other를 선택하여 오브젝트

리포지토리에서 Delphi Projects의 Delphi Files에 있는 Reconcile Error Dialog 아이콘을 선택합니다.

27Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

이 아이콘을 선택하고 OK를 클릭하면, 새로운 유닛 RecError.pas가 DataSnapClient 프로젝트에

추가됩니다. 이 유닛에는 데이터베이스 업데이트 에러를 해결하기 위한 업데이트 에러 다이얼로그

(ReconcileErrorForm)의 선언과 정의가 있습니다.

28Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

ReconcileErrorForm의 인스턴스는 필요할 때마다 즉석에서 동적으로 생성됩니다. 그러면 이 ReconcileErrorForm을 언제, 혹은 어떻게 사용하는가? 매우 간단합니다. 업데이트가 성공하지 못한 각

레코드에 대해(이유가 무엇이든), TClientDataSet 컴포넌트의 OnReconcileError 이벤트 핸들러가

호출됩니다. TClientDataSet의 이 이벤트 핸들러는 다음과 같이 정의됩니다.

procedure TForm2.ClientDataSet1ReconcileError(DataSet: TClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);

이 이벤트 핸들러에는 4 개의 인자가 있습니다. 첫 번째는 에러가 발생한 TClientDataSet 컴포넌트, 두

번째는 에러의 원인에 대한 메시지를 포함한 특정 ReconcileError 에러 객체, 세 번째는 에러가 발생한

데이터 동작을 나타내는 UpdateKind (입력/삭제/수정), 네 번째는 어떤 처리를 할 것인지의 Action 입니다.

Action 값으로 아래의 값들 중 하나를 리턴할 수 있습니다. (순서는 실제 열거 순서)

- raSkip – 이 레코드를 업데이트하지 않습니다. 그러나 적용되지 않은 수정 내용이 수정 로그(change

log)에 남아있습니다. 다음 번에 다시 시도하도록 합니다.

- raAbort - 전체 조정 처리를 중단합니다. 더 이상 OnReconcileError 이벤트 핸들러에 레코드가 전달되지

않습니다.

- raMerge – 데이터베이스의 현재 레코드와 업데이트된 레코드를 합칩니다(merge). 여러분 측에서 수정된

대로 단순히 원격 데이터베이스의 필드 값을 변경합니다.

- raCorrect - 업데이트된 레코드를 이벤트 핸들러에서(또는 ReconcileErrorForm 다이얼로그 안에서)

정정한 레코드 값으로 대치합니다. 이것은 사용자 조정(예를 들면 타이핑)이 필요한 옵션입니다.

- raCancel – 이 레코드 안의 모든 변경 사항을 취소하고, 원래의 (로컬) 레코드로 다시 돌아갑니다.

- raRefresh – 이 레코드 안의 모든 변경 사항을 취소하고, 원격의 데이터베이스로부터 현재 레코드

값들을 다시 로드합니다. (이전에 가지고 있던 로컬 레코드가 아님)

ReconcileErrorForm의 장점은, 이 모든 것에 대해 개발자가 일일이 관여할 필요가 없다는 것입니다.

여러분은 단지 두 가지만 하면 됩니다. 첫 번째 할 일은, DataSnap 클라이언트 메인 폼의 정의 부분에

RecError 유닛을 포함해야 합니다. DataSnap 클라이언트 폼이 나타난 상태에서 메뉴에서 File | Use Unit 를 선택하여 Use Unit 다이얼로그를 띄웁니다. 클라이언트 폼이 현재 폼인 상태에서 Use Unit

다이얼로그를 띄우면 현재 유닛을 제외한 다른 유닛들만 나타나게 되는데, 여기서는 RecError 뿐입니다.

이 유닛을 선택하고 OK를 클릭하면 됩니다.

두 번째 할 일은, OnReconcileError 이벤트 핸들러에서 RecError 유닛의 HandleReconcileError 함수를

호출하는 것입니다. HandleReconcileError 함수는 OnReconcileError 이벤트 핸들러와 동일한 4 개의

인자를 가지고 있으므로(물론 우연의 일치가 아니죠), 각각의 인자를 그냥 넘기기만 하면 됩니다. 따라서,

TClientDataSet 컴포넌트의 OnReconcileError 이벤트 핸들러는 아래와 같이 코딩하게 됩니다.

procedure TFrmClient.ClientDataSet1ReconcileError(DataSet: TClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction); begin Action := HandleReconcileError(DataSet, UpdateKind, E); end;

3.2.4. 에러 조정 데모

이제 이렇게 코딩한 내용이 실제 상황에서는 어떻게 동작할까요. 이것을 테스트하기 위해서는, 당연히

동시에 실행되고 있는 둘 이상의 DataSnap 클라이언트 애플리케이션이 필요합니다. 지금까지 작성한

DataSnap 클라이언트 및 DataSnap 서버 애플리케이션을 완벽하게 테스트하기 위하여, 다음의 단계들을

수행해야 합니다.

- DataSnap 서버 애플리케이션을 시작합니다.

- 첫 번째 DataSnap 클라이언트를 시작하고, 연결 버튼을 클릭합니다.

- 두 번째 DataSnap 클라이언트를 시작하고, 연결 버튼을 클릭합니다. 실행 중인 동일한 서버로부터

29Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

데이터를 가져올 것입니다.

- 첫 번째 DataSnap 클라이언트에서 첫 번째 레코드의 "FirstName" 필드를 수정합니다.

- 두 번째 DataSnap 클라이언트에서 역시 첫 번째 레코드의 "FirstName" 필드를 수정합니다.

- 첫 번째 DataSnap 클라이언트의 "Apply Updates" 버튼을 클릭합니다. 모든 업데이트 내용이 아무 문제

없이 적용될 것입니다.

- 두 번째 DataSnap 클라이언트의 "Apply Updates" 버튼을 클릭합니다. 이번에는, 하나 혹은 그 이상의

에러가 발생할 것입니다. 그 이유는 첫 번째 레코드가 (다른 DataSnap 클라이언트에 의해) 변경된

"FirstName" 필드 값을 갖고 있어서 레코드가 충돌해서 OnReconcileError 이벤트 핸들러가 호출되기

때문입니다.

- Update Error 다이얼로그(ReconcileErrorForm)에서 Skip, Abort, Merge, Correct, Cancel, Refresh

등의 조정(reconcile) 액션들을 직접 사용해 보면 이 액션들이 어떤 동작을 하는지 제대로 느껴볼 수

있습니다. Skip과 Cancel의 차이점, 그리고 Correct, Refresh와 Merge의 차이점에 특별히 주의해서

살펴보십시오.

Skip 은 요청했던 업데이트를 건너뛰어 다음 레코드로 넘어갑니다 (당분간). 적용되지 않은 수정 내용은

수정 로그(change log)에 남아 있게 됩니다. Cancel 또한 요청했던 업데이트를 건너뛰지만, 동일한

업데이트 패킷 내의 뒤이은 모든 업데이트를 취소합니다. 현재의 업데이트 요청은 두 경우 모두

건너뛰지만, Skip은 다른 업데이트 요청을 계속 진행하고, Cancel은 전체 ApplyUpdates 요청을

취소합니다.

Refresh 는 여러분이 레코드를 수정한 모든 업데이트 내용을 버리고 서버 데이터베이스의 현재 값으로

레코드를 리프레시합니다. Merge 는 서버 레코드 안에 여러분이 수정한 내용을 반영하여 서버의 레코드와

업데이트 레코드를 합치려고 시도합니다. Refresh와 Merge는 더 이상 수정 요청을 하지 않게 되므로

Refresh나 Merge 후에는 레코드들이 일치되게 됩니다. (반면, Skip이나 Cancel을 한 후에는 수정 요청을

다시 시도할 수 있습니다)

Correct는 가장 강력한 옵션으로서, 이벤트 핸들러 내에서 업데이트 내용을 임의로 지정할 수 있게

해줍니다. 이 액션을 사용하려면, 약간의 코드를 직접 작성하거나, 혹은 다이얼로그에 값을 입력해야

합니다.

3.3. DataSnap Database 배포

데이터베이스를 사용하는 DataSnap 서버의 배포는 우리가 연습해봤던 단순한 DataSnap 서버의 경우보다

좀 더 복잡할 수 있습니다. 클라이언트 애플리케이션의 경우는 바뀌는 것이 없습니다. 여전히 가볍고(thin)

간결한(smart) 애플리케이션이며, uses 절에 MidasLib 유닛을 추가하면 단독 실행 파일로도 배포할 수

있습니다.

DataSnap 서버의 경우에는 데이터베이스 드라이버도 함께 배포해야 합니다. 어떤 드라이버와 파일을

함께 배포해야 하는지는 선택한 데이터베이스에 따라 다릅니다. DBX4를 사용하는 경우 TSQLConnection

컴포넌트를 체크해야 하며, dbxconnections.ini 및 dbxdrivers.ini 파일도 체크해야 합니다. 이 파일들은

윈도우 XP의 경우 C:₩Documents and Settings₩All Users₩ Documents₩RAD Studio₩dbExpress

₩7.0 디렉토리에, 그리고 윈도우 비스타 및 윈도우 7의 경우에는 C:₩Users₩Public₩Documents₩RAD

Studio₩dbExpress₩7.0 디렉토리에 있습니다.

dbxdrivers.ini 파일에는 특정 드라이버에 대해 DriverPackageLoader 및 MetaDataPackageLoader (보통

같은 패키지가 지정됩니다)가 지정되어 있습니다. BlackfishSQL의 경우 DBXClientDriver140.bpl이며,

따라서 이 파일을 BlackfishSQL 자체와 함께 배포해야 합니다. BlackfishSQL 배포에 관한 더 자세한

내용은 RAD Studio\7.0 디렉토리에 있는 deploy_en.htm 파일을 참고하십시오.

30Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

3.4. 기존의 리모트 데이터모듈 재사용

기존의 TRemoteDataModule 클래스를 가지고 있는 경우, 새로운 DataSnap와 함께 사용할 수는 있지만

서버에서 일부 기능, 특히 COM 관련 부분들을 삭제해야 합니다.

먼저, 마이그레이션 하려고 하는 것이 리모트 데이터모듈이 아니라 DataSnap 서버 애플리케이션이라면,

가장 먼저 실행파일을 /unregister 옵션과 함께 커맨드라인에서 실행하여 등록 해제(unregister)를 해야

합니다. 이 절차를 먼저 하지 않으면, 리모트 데이터모듈을 레지스트리에서 등록 해제할 방법이

없어집니다. (차후에 하려면 프로젝트의 예전 백업본으로 다시 실행파일을 만들어 등록 해제해야 합니다)

리모트 데이터모듈의 유닛에서 initialization 섹션의 코드를 지워야 합니다. 해당 유닛을 델파이 2007 이하

버전과 델파이 2009 이상 버전 모두에서 사용하려면, 아래와 같이 코드를 {$IFDEF}로 감싸면 됩니다.

{$IF CompilerVersion >= 20} initialization TComponentFactory.Create(ComServer, TRemoteDataModule2010, Class_RemoteDataModule2010, ciMultiInstance, tmApartment); {$IFEND} end.

프로젝트에서 UpdateRegistry 루틴도 제거해야 하며, 역시 {$IFDEF}로 감쌀 수도 있습니다.

{$IF CompilerVersion >= 20} class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string); override; {$IFEND}

프로젝트를 COM을 사용하지 않는 DataSnap 서버로 전환시키기 위해 해야 할 가장 중요한 작업은 타입

라이브러리(.ridl 파일)와 타입 라이브러리 임포트 유닛을 제거하는 것입니다. 이 부분들은 {IFDEF} 처리를

이용해서 남겨놓을 수가 없습니다, 따라서 DataSnap 서버를 Delphi 2007 이하 버전과 Delphi 2009 이상

버전으로 양쪽 모두 유지해야 한다면 프로젝트의 복사본을 만들어야 합니다. 앞에서 했던 것처럼,

DataSnap 서버 애플리케이션에서 TDSServerClass 컴포넌트를 사용하여 TRemoteDataModule 클래스를

리턴해야 합니다.

마지막으로, TRemoteDataModule에 추가로 코딩했던 모든 메소드들을 protected 섹션(COM 기반

DataSnap에서 디폴트임)에서 public 섹션으로 옮겨야 합니다. (이렇게 해야 COM을 사용하지 않는

DataSnap 아키텍처에서 메소드 정보가 생성될 수 있게 됩니다)

4. DataSnap 필터

이 장에서는 필터가 어떻게 동작하는지, 압축(compression) 등의 내장된 필터를 어떻게 사용할 수 있는지,

그리고 어떻게 직접 새로운 DataSnap 필터를 개발할 수 있는지 등을 설명하겠습니다. DataSnap 필터는

통신 흐름을 가로채는 특별한 DLL로서, 여러 필터들을 동시에 사용할 수도 있습니다. 예를 들면 압축과

암호화, 혹은 로깅과 압축을 동시에 할 수 있습니다.

DataSnap 서버와 클라이언트에서 필터를 사용하려면 두 군데에서 필터를 지정해야 합니다. 서버에서는

TDSTCPServerTransport 컴포넌트의 Filters 속성에서 필터들을 지정해야 합니다. 또한 클라이언트에서는

DataSnap 클라이언트 프로젝트의 uses 절에서 필터들을 지정해야 합니다. 클라이언트는 이것으로

충분합니다. 왜냐하면 각 DataSnap 필터는 스스로 자동으로 등록되기 때문입니다.

OnConnect 이벤트 핸들러가 실행되는 시점에 연결에서 사용되는 등록된 필터들을 알아볼 수 있습니다.

예를 들면 다음과 같습니다. (LogInfo 함수는 로그 파일에 정보를 써넣기 위한 사용자 함수입니다)

procedure TServerContainer1.DSServer1Connect( DSConnectEventObject: TDSConnectEventObject);

31Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

var i: Integer; begin Info(' nnect ' + DSConnectEventObject.ChannelInfo.Info)Log Co ; for i:=0 to DSConnectEventObject.Transport.Filters.Count-1 do LogInfo(' Filter: ' + DSConnectEventObject.Transport.Filters.GetFilter(i).Id); end;

4.1. ZlibCompression 필터

예제로서 기존의 DataSnap 필터를 살펴봅시다. 이것은 델파이 2010에 기본으로 내장된 것으로,

DataSnap 서버와 클라이언트 사이의 데이터 스트림을 압축해주는 역할을 합니다. 이 필터의 이름은

ZlibCompression 필터로, DbxCompressionFilter 유닛에 있습니다.

TCP/IP를 위한 TDSTCPServerTransport 컴포넌트와 HTTP를 위한 DSHTTPService 컴포넌트 모두

TTransportFiltersCollection 타입의 Filters 속성을 가지고 있습니다. 필터 콜렉션을 편집하려면 Filters

속성의 엘립시스(…) 버튼을 클릭합니다. 이 다이얼로그에서 새로운 TTransportFilterItem을 추가할 수

있는데, 오브젝트 인스펙터에서 FilterId와 선택적인 옵션을 지정할 수 있습니다. ZLibCompression 필터는

델파이 2010에 기본적으로 내장되어 있으며, TTransportFilterItem의 FilterId로 지정할 수 있습니다.

서버 측에서 TDSTCPServerTransport 컴포넌트에 Filters 속성에 지정하는 것과 별도로, 클라이언트

측에서도 이 필터를 지정해야 한다는 것을 기억하십시오(보내는 요청을 압축하고 돌아오는 응답을 압축

해제하기 위해). 이를 위해서는 ClientForm의 uses 절에 DbxCompressionFilter 유닛을 추가하기만 하면

됩니다. 그러면 TTransportCompressionFilter가 자동으로 등록되고 서버와의 통신에 사용되게 됩니다.

uses 절에 DbxCompressionFilter 유닛을 추가하지 않으면, 클라이언트를 실행할 때 "Communication

filter ZLibCompression is not registered. Filter class needs to be registered in order to communicate

with the server." (통신 필터

ZLibCompression가 등록되지

않았습니다. 서버와 통신하기

위해서는 필터 클래스가 등록되어

있어야 합니다) 라는 메시지의

예외가 발생할 것입니다.

32Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

4.2. 로그 필터

DataSnap 2010에서는 개발자들이 직접 자신만의 전송 필터를 정의할 수 있습니다. TTransportFilter

타입에서 파생하는 새로운 클래스를 만들면 됩니다. 이 새로운 클래스에서 메소드들을 오버라이드하여

새로 구현할 수 있습니다. 예를 들면, 다음과 같이 TLogFilter 클래스를 만들 수 있습니다.

unit LogFilter; interface uses SysUtils, DBXPlatform, DBXTransport; type TLogFilter = class(TTransportFilter) private protected function GetParameters: TDBXStringArray; override; function GetUserParameters: TDBXStringArray; override; public function GetParameterValue(const ParamName: UnicodeString): UnicodeString;override;

function SetParameterValue(const ParamName: UnicodeString; const ParamValue: UnicodeString): Boolean; override; constructor Create; override; destructor Destroy; override; function ProcessInput(const Data: TBytes): TBytes; override; function ProcessOutput(const Bytes): TBytes; override; Data: T function Id: UnicodeString; override; end; const LogFilterName = 'Log';

이 클래스의 구현 부분 대부분을 비워놓는데, 이 로그 필터의 유일한 목적이 ProcessInput과

ProcessOutput 메소드에서 보내지는 데이터를 로깅하는 것이기 때문입니다. 비어있지 않은 메소드의

구현은 다음과 같습니다.

function TLogFilter.SetParameterValue(const ParamName, ParamValue: UnicodeString): Boolean;

begin Result := True; end; constructor TLogFilter.Create; begin inherited Create; end; destructor TLogFilter.Destroy; begin inherited Destroy; end; function TLogFilter.ProcessInput(const Data: TBytes): TBytes; begin Result := Data; // 들어오는 데이터를 로깅함 end; function TLogFilter.ProcessOutput(const Data: TBytes): TBytes; begin Result := Data; // 나가는 데이터를 로깅함 end;

33Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

function TLogFilter.Id: UnicodeString; begin Result := LogFilterName; end;

마지막으로, DataSnap 전송 필터의 구현에서 중요한 부분은 initialization 섹션과 finalization 섹션에서의

등록 부분입니다. 이렇게 하면 DataSnap 클라이언트가 전송 필터를 찾을 수 있게 되고, 필요할 때 사용할

수 있게 됩니다.

initialization TTransportFilterFactory.RegisterFilter(LogFilterName, TLogFilter);

finalization TTransportFilterFactory.UnregisterFilter(LogFilterName);

end.

앞에서 언급했던 것처럼, DataSnap 서버에서 전송 필터를 사용하기 위해서는 TDSTCPServerTransport나

TDSHTTPService 컴포넌트의 필터 리스트에 필터를 추가해야 합니다. ZLibCompression 필터는 디자인

시점에 이미 알려져 있는 필터지만 새로운 필터는 그렇지 않습니다 (디자인 시에 디자인타임 패키지에

추가하고 인스톨 하지 않는 한). 다행히 ServerContainerUnitDemo의 uses 절에 필터의 유닛을 추가한 후

수동으로 필터 리스트에 필터 이름을 추가하면 실행 중에 전송 필터를 추가 할 수 있습니다.

procedure TServerContainer1.DataModuleCreate(Sender: TObject); begin DSTCPServerTransport1.Filters.AddFilter(LogFilterName); DSHTTPService1.Filters.AddFilter(LogFilterName); DSHTTPService1.Active := True; end;

이렇게 하면 서버가 LogFilter를 사용하게 되며, 클라이언트의 경우는 클라이언트의 uses 절에 LogFilter

유닛을 추가하면 자동으로 필터를 사용하게 됩니다. 이렇게 하지 않으면, 아래와 같은 에러 메시지가

나타날 것입니다.

동일한 로깅 필터가 사용되더라도 DataSnap 서버와 클라이언트 애플리케이션 각각은 자체 로그 파일을

가지고 있을 것이므로, ParamStr(0)과 같은 정보를 로그 메시지에 포함시킬 필요는 없습니다.

4.3. 암호화 필터

4.2 장에서 다룬 간단한 필터 예제에서 봤듯이, 여러분이 직접 자신만의 더 복잡한 DataSnap 필터를

개발하는 것은 그렇게 어려운 일이 아닙니다. 사실, 이미 많은 서드파티 필터들이 이미 나와 있으며,

Daniele Teti는 9 개나 되는 DataSnap 2010 필터들이 포함된 DataSnap Filters Compendium을

http://www.danieleteti.it/?p=168 페이지에서 제공하고 있습니다. 이 필터들은 세 그룹으로 나뉘어지는데,

해시(Hash) 그룹은 MD5, MD4, SHA1 and SHA512를 지원하고, 암호화(Cipher) 그룹은 Blowfish,

Rijndael, 3TDES, 3DES를 지원하며, 압축(Compress) 그룹은 LZO를 지원합니다. 전체 소스 코드도

제공됩니다.

34Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

5. DataSnap 웹 애플리케이션

윈도우 타겟 애플리케이션과 별개로, ISAPI, CGI 또는 웹 애플리케이션 디버거 타겟 애플리케이션을

개발하기 위한 위저드도 제공됩니다. 먼저 각각의 타겟들의 장점에 해서 살펴볼 것이며, 또한 이들 3 가지

타겟들의 프로젝트들을 개발자가 작성하는 DataSnap 유닛들을 공유하는 하나의 프로젝트 그룹으로

만들어 동일한 DataSnap 서버 객체에 대한 세 가지 타겟들을 만들어내는 방법을 설명하겠습니다.

지금까지 작성한 DataSnap 애플리케이션이 잘 동작하기는 하지만, 이런 서버 애플리케이션을 배포할 수

없는 경우가 있습니다. 예를 들면 방화벽에서 클라이언트가 서버에 연결하기 위해 필요한 포트를 열도록

허용하지 않는 경우도 있습니다. 다행히도, 이런 경우들의 대부분은 웹 서버에서 운영중인 웹 사이트가

있어서 일반적으로 웹 서버를 위한 80 포트는 열려 있습니다. 마이크로소프트의 인터넷 정보 서비스

(IIS)가 웹 서버로 사용되는 경우라면, 새로운 DataSnap 웹 브로커 애플리케이션 위저드를 이용하여

IIS에서 운영할 수 있는 프로젝트를 만들 수 있습니다.

DataSnap 웹 브로커 애플리케이션 위저드는 3 가지 선택을 제공하는데, 그 중 하나는 실제 웹 브로커

애플리케이션이 아니라 디버깅 목적으로만 사용됩니다. Web App Debugger executable 옵션은 매우

강력한 디버깅 방법인데, 웹 애플리케이션 디버거 클라이언트 DataSnap 애플리케이션을 디버깅할 때

Web App Debugger(델파이 IDE의 툴 메뉴에서 실행 가능)를 호스트 애플리케이션으로 사용할 수 있기

때문입니다. CGI나 ISAPI/NSAPI 웹 애플리케이션의 디버깅은 훨씬 어렵습니다. 따라서 애플리케이션을

개발 진행중인 상황에서는 Web App Debugger가 강력한 선택입니다.

다른 옵션들, 즉 ISAPI/NSAPI Dynamic Link Library 및 CGI Stand-alone executable은 실제로 운영될

DataSnap 서버 프로젝트가 필요할 때 선택할 수 있습니다.

35Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

그러나 CGI Stand-alone executable은 들어오는 요청마다 실행 파일을 로드 및 언로드 하기 때문에 좋은

방법이 아니라는 점을 기억해두십시오. 따라서 매번 데이터베이스에 연결하는 지연 시간이 소요되게 되며,

이 애플리케이션 타입이 수반할 성능 문제에 대해 고민하게 될 수도 있습니다.

ISAPI 타겟을 사용하면 단 한번만 로드되고 메모리에 그대로 유지되는 DLL 파일로 생성되므로, 뒤이은

요청들은 추가적인 성능 저하 문제를 겪지 않게 됩니다. ISAPI DLL의 주요 단점은 기존의 DLL을 교체하는

것이 쉽지 않다는 것입니다만(웹 서버 접근 방법이 FTP 뿐인 경우), 이 문제를 해결하기 위한 ISAPI

매니저들이 충분히 있습니다. (자세한 사항은 여러분의 웹 호스팅 업체에 문의해보십시오)

ISAPI DLL의 또 다른 단점은 디버깅하는 것이 쉽지 않다는 것입니다. 호스트 애플리케이션으로 IIS를

로드해야 하는데, 항상 기대한 대로 동작하지는 않습니다. 그러나 이 문제는 Web App Debugger

executable 타입으로 이 문제를 해결 할 수 있습니다. 2 개의 프로젝트를 만들고 둘 다 동일한 코드를

사용하도록 하면 됩니다. 이제 이 타겟을 첫 번째 예제로 선택하고, 몇 가지 실제 개발에서 쓸 만한

테크닉들을 추가해보겠습니다.

5.1. 웹 애플리케이션 디버거 타겟

먼저, New DataSnap WebBroker Application 위저드를 사용하여 새로운 웹 앱 디버거 애플리케이션을

생성합니다. Class Name에 DS-WAD 처럼 뭔가 지정하고 “ Support HTTP Authentication” 옵션을

체크합니다.

36Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

OK를 클릭하면, 3 개의 유닛을 갖는 새로운 프로젝트가 생성됩니다. 여러분의 디폴트 프로젝트

디렉토리에 Project1과 Unit1 이름을 가진 파일이 없는 경우라면 프로젝트는 Project1으로, 유닛들은 각각

Unit1, ServerMethodsUnit1, Unit2라고 이름이 부여되었을 것입니다.

첫 번째 유닛은 빈 폼인데, 이것은 Web App Debugger executable에만 있으며, 다른 웹 타겟에서는 물론

필요 없는 것입니다. 이 유닛을 WADForm.pas로 저장합시다. 두 번째 유닛 ServerMethodsUnit1.pas는

서버 모듈을 포함하는데, 다이얼로그에서 지정했던 TDSServerModule로부터 파생된 클래스입니다.

우리는 곧 이 유닛으로 돌아올 것이지만, 일단 먼저 주어진 이름 ServerMethodsUnit1.pas로 그대로

저장합니다. 세 번째 Unit2는 웹 모듈인데 4 개의 컴포넌트들이 미리 배치되어 있습니다 ("Support HTTP

Authentication" 옵션을 체크하지 않았다면 3개). 이 것은 들어오는 요청을 받아 프로젝트에 포함된

DataSnap 서버 모듈들에 분배하는 유닛입니다. 이 유닛을 DSWebMod.pas로 저장합니다.

마지막으로, DataSnap Web App Debugger Server라는 것을 의미하는 이름인 DSWADServer.dproj로

프로젝트를 저장합니다.

5.2. ISAPI 타겟

ServerMethodsUnit1.pas 및 DSWebMod.pas 유닛에 본격적으로 작업을 하기 전에, 먼저 프로젝트

그룹에 새로운 프로젝트를 추가해야 하는데, 먼저 ISAPI/NSAPI Dynamic Link Library부터 해봅시다.

따라서 프로젝트 매니저에서 ProjectGroup 항목을 오른쪽 마우스 클릭하고 Add New Project를 선택하여

새 프로젝트를 시작하기 위한 오브젝트 갤러리를 띄웁니다. DataSnap 서버 페이지에서 다시 New

DataSnap WebBroker Application 위저드를 이용하여 새로운 ISAPI/NSAPI DLL 프로젝트를 생성합니다.

이번에는 DSWADServer 프로젝트의 기존 유닛을 재사용할 것이므로, 다이얼로그의 아래쪽에 있는

옵션들을 수정할 필요가 없습니다.

37Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

OK를 클릭하면 새로운 프로젝트를 생성되고 기존의 프로젝트 그룹에 추가될 것이며, 이 프로젝트에는

유닛 ServerMethodUnit2.pas 및 Unit1.pas가 추가되어 있을 것입니다.

, 새로운 유닛 ServerMethodUnit2.pas와 Unit1.pas를 사용하는 대신, 기존의 DSWADServer 프로젝트에

포함되어 있는 유닛 ServerMethodUnit1.pas와 DSWebMod.pas를 사용해야 합니다. 따라서 Project1.dll

항목 아래의 ServerMethodUnit2.pas 항목에서 오른쪽 마우스 클릭하여 Remove from Project를

선택합니다. 확인 다이얼로그에서 OK를 클릭합니다(아직 저장하지 않았다면 디스크에서

ServerMethodUnit2.pas와 .dfm 파일을 삭제할 필요 없습니다). Unit1.pas도 같은 방법으로 삭제하며,

따라서 Project1.dll에는 더 이상 포함된 유닛이 없게 됩니다. 다음으로 Project1.dll에서 오른쪽 마우스

클릭하여 DSWebMod.pas와 ServerMethodUnit2.pas 모두를 이 프로젝트에 추가합니다. 마지막으로,

Project1을 DSISAPIServer.dproj로 이름을 변경하여 프로젝트 그룹을 완성합니다.

이제 아래 그림처럼 DSWebMod 와 DSSererMethodUnit1.pas 유닛을 공유하는 두 프로젝트를 포함하는

하나의 프로젝트 그룹이 되었을 것입니다.

38Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

이 구성으로 두 프로젝트를 빌드할 수 있게 되며, DSWADServer를 사용하여 테스팅과 디버깅을 할 수 있고

DSISAPIServer를 사용하여 IIS에 실제 운영을 위한 DataSnap 서버 배포를 할 수 있습니다.

ServerMethodsUnit1에 웹 메소드를 추가하기 전에, TDSServerModule의 자동 인스턴스를 생성하는

코드를 프로젝트 파일에서 삭제해야 합니다. TDSServerModule은 웹 모듈과 마찬가지로 궁극적으로는

데이터모듈이기 때문에, ISAPI DLL을 실행하려고 하면 에러 메시지가 나타날 것입니다. 웹 브로커

애플리케이션에서는 단 하나의 웹 모듈만 있어야 하기 때문입니다. DSISAPIServer.dpr 프로젝트의 소스

코드를 열어서, 다음과 같이 begin~end 블록을 수정합니다:

begin CoInitFlags := COINIT_MULTITHREADED; Application.Initialize; Application.CreateForm(TWebModule2, WebModule2); // Application.CreateForm(TServerMethods1, ServerMethods1); Application.Run; end.

이렇게 하면 하나의 데이터모듈만 허용된다는 에러 메시지를 피할 수 있을 것입니다. 실제 배포된 ISAPI

DLL을 실행했을 때 이 에러 메시지가 나타나는 대신 단순한 서버 에러나 타임 아웃이 발생할 수도 있기

때문에, 이 문제를 기억해두는 것이 중요합니다.

5.3. 서버 메소드, 배포와 클라이언트

기능을 추가할 때는 ServerMethodUnit1.pas 유닛에만 작업을 하게 됩니다. 기본적으로 하나의 샘플

메소드가 이미 포함되어 있지만, DataSnap 서버의 윈도우 버전과 마찬가지로 두 개의 메소드를 더 추가할

수 있습니다. (서버 메소드 유닛에 필요한 컴포넌트들과 소스 코드에 대해서는 2.1.4을 참고하십시오)

서버 메소드를 구현하고 나면 ISAPI DLL을 마이크로소프트 인터넷 정보 서비스 등의 웹 서버에 배포할 수

있습니다. 이에 대해 Jim Tierney의 글 http://blogs.embarcadero.com/jimtierney/2009/08/20/31502 에

자세히 설명되어 있으므로, 그 내용을 똑같이 반복하지는 않겠습니다.

39Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

배포할 수 있는 웹 서버를 가지고 있지 않다면, 필자의 서버에 배포된 DataSnap ISAPI 서버를 테스트해볼

수 있습니다. 필자는 DataSetProvider를 노출시키지도 않았고 GetEmployees 메소드에서는 데이터를

리턴하도록 하지도 않지만, ServerTime과 EchoString 메소드는 제대로 동작하고 있으므로 이 서버에 대한

테스트 DataSnap 클라이언트를 작성해보기에는 충분합니다.

클라이언트 애플리케이션에서 ISAPI DataSnap 서버로 연결하기 전에, 데이터 익스플로러를 이용하여

ISAPI DataSnap 서버와 연결이 되는지 확인해보는 것도 좋은 방법입니다. 데이터 익스플로러에는

DATASNAP이라는 새 카테고리를 가지고 있으며, 그 카테고리를 열어보면 DATASNAPCONNECTION

이라는 커넥션이 있습니다. 이 커넥션 항목은 마우스 오른쪽 클릭하고 Modify Connection를 선택하여

수정할 수 있습니다.

이 다이얼로그에서는 Protocol, Host, Port, 그리고 서버에 있는 ISAPI DataSnap 서버 애플리케이션을

가리키는 URL Path를 지정할 수 있습니다. Path에 cgi-bin/DSISAPIServer.dll 을 지정한 후 Test

Connection를 클릭하여 잘 동작하는지 확인합니다. (웹 서버가 없다면 www.bobswart.nl 호스트로

테스트할 수 있습니다)

이제, OK를 클릭하여 다이얼로그를 닫고, 데이터 익스플로러에서 DATASNAPCONNECTION 항목을

펼쳐서 Tables, Views, Procedures, Functions and Synonyms 등을 살펴봅니다. 아래 그림에서 보이는

것처럼, Procedures 항목의 아래에는 우리가 작성했던 EchoString, ServerTime ,GetEmployees 뿐만

40Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

아니라 DSAdmin, DSMetaData, TServerMethods1.AS_xxx 등도 포함되어 있습니다.

DataSnap 클라이언트 애플리케이션 작성하지 않아도 이 메소드들을 테스트해볼 수 있습니다. 여기서는

그 예로서, EchoString 메소드에서 보낸 값이 다시 돌아오는지 테스트 해봅시다.

TServerMethods1.GetEmployees 프로시저에서 오른쪽 마우스 킅릭하고 "View Parameters"을

선택합니다. 이렇게 하면 IDE에 새 윈도우가 나타나며, 여기에 Value 파라미터에 대한 값(예를 들어

"42")을 입력할 수 있습니다. 이 창에서 오른쪽 마우스 클릭하고 "Execute"를 선택하면 리모트 서버

메소드가 실행됩니다. 그 결과는 아래쪽에 ReturnValue로 나타납니다.

41Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

이로써 DataSnap 서버로부터 개발자가 작성한 서버 메소드를 호출할 수 있다는 것을 알 수 있습니다.

DataSnap 클라이언트가 서버에 접속하기 위해서는 TSQLConnection 속성들만 수정하면 됩니다.

이전에는 DataSnap 서버의 윈도우 버전에 연결했지만, 이제는 웹 버전으로 연결하기 위하여 이 설정들을

수정해야 합니다.

필자의 웹 서버에 있는 DSISAPIServer.dll를 사용하려면, DataSetProvider를 동작하지 않게 했고

GetEmployees 메소드에서 데이터를 리턴하지 않는다는 것을 기억해두십시오. 하지만 ServerTime 과

EchoString 메소드는 호출할 수 있습니다.

42Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

6. REST 와 JSON

DataSnap 2010에서는 REST와 JSON을 지원합니다. DataSnap 2010에서는 DataSnap HTTP 요청에

대해 REST를 지원합니다. 예를 들어서, 만일 DataSnap 서버의 URL이 http://www.bobswart.nl/cgi-

bin/DSISAPIServer.dll 이라면, 이 URL에 /datasnap/rest를 덧붙이고 그 뒤에 서버 메소드 클래스의

이름과 메소드 이름, 인자들을 덧붙이면 됩니다.

일반적인 문법은 다음과 같습니다.

http://server/datasnap/rest/<class>/<method>/<parameters>

필자의 서버의 DSISAPIServer.dll의 TServerMethod1 모듈에 있는 ServerTime 메소드의 URL의 경우

다음과 같습니다.

http://www.bobswart.nl/cgi-bin/DSISAPIServer.dll/datasnap/rest/TServerMethods1/ServerTime

이런 REST URL을 호출하면 그 결과는 JSON으로 리턴됩니다. 웹 브라우저에서 요청을 해보면 다음과

같이 나타납니다.

위에서 웹 브라우저에 보이는 결과가 JSON 구조입니다.

{"result":["2009-10-16 16:01:33.145"]}

마르코 칸투(Marco Cantù)가 쓸 Delphi 2010과 REST 클라이언트에 대한 백서에서 REST에 대해 더

자세하게 다뤄질 것입니다.

6.1. 콜백(Callback)

JSON은 DataSnap 서버에 대한 REST 호출의 결과에서 사용되는 것 외에, 콜백 메소드를 구현하는 데에도

사용됩니다. DataSnap 2010은 클라이언트 측 콜백 함수를 지원하며, 서버 메소드의 컨텍스트에서

실행됩니다. 이것은 서버 메소드(DataSnap 클라이언트에서 호출됨)가 실행되는 동안, 클라이언트가 서버

메소드로 인자로서 전달한 콜백 함수를 서버가 호출할 수 있다는 것을 의미합니다.

예제로, EchoString 메소드를 수정하여 콜백 함수를 추가해 보겠습니다. EchoString 메소드의 정의

부분을 다음과 같이 수정합니다.

function EchoString(Value: string; callback: TDBXcallback): string;

TDBXcallback 타입은 DBXJSON 유닛에 정의되어 있습니다. 새로운 EchoString 메소드를 구현하기 전에,

먼저 클라이언트 측에서 콜백 메소드(서버로부터 호출될 클라이언트 메소드)가 어떻게 정의되는지

살펴봅시다.

43Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

클라이언트 측에서, TDBXCallback에서 파생되는 새로운 클래스를 선언하고, Execute 메소드를

오버라이드 합니다.

type TCallbackClient = class(TDBXCallback) public function Execute(const Arg: TJSONValue): TJSONValue; override; end;

Execute 메소드 안에서, TJSONValue 타입의 Arg 인자를 받게 되며 이것을 클론(clone)하여 실제 내용에

접근할 수 있습니다. Execute 메소드는 자신인 TJSONValue 자체를 리턴할 수 있으므로, 동일한 값을 다시

리턴하도록 코딩하겠습니다.

function TCallbackClient.Execute(const Arg: TJSONValue): TJSONValue; var Data: TJSONValue; begin Data := TJSONValue(Arg.Clone); ShowMessage('Callback: ' + TJSONObject(Data).Get(0).JSonValue.value); Result := Data; end;

이 예제에서, 위의 콜백 메소드는 EchoString 메소드가 실제로 리턴되기 전에(예를 들어 메소드가 아직

실행되고 있는 동안) EchoString 메소드로 전달된 값을 보여줄 것입니다.

서버 측의 새로운 EchoString 메소드의 구현에서는, 다음과 같이 TJSONObject 안에 스트링 값을 넣어

callback.Execute 메소드에 전달합니다:

function TServerMethods2.EchoString(Value: string; callback: TDBXcallback): string; var msg: TJSONObject; pair: TJSONPair; begin Result := Value; msg := TJSONObject.Create; pair := TJSONPair.Create('ECHO', Value); pair.Owned := True; msg.AddPair(pair); callback.Execute(msg); end;

서버 쪽에서 실제 EchoString 메소드가 끝나기 전에 클라이언트 쪽에서 콜백 함수가 실행되고 리턴된다는

점을 주목하십시오.

마지막으로, 콜백 클래스(새로운 TCallbackClient의 인스턴스)를 두 번째 인자로 전달해야 하므로,

클라이언트 측의 EchoString 메소드 호출도 역시 수정해야 합니다.

var MyCallback: TCallbackClient; begin MyCallback := TCallbackClient.Create; try Server.EchoString(Edit1.text, MyCallback); finally MyCallback.Free; end;

end;

이 간단한 예제를 통해 DataSnap 2010에서 클라이언트 측 콜백 메소드를 사용하는 방법을 살펴봤습니다.

44Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

7. DataSnap 과 .NET

델파이 프리즘 2010으로 이전에 우리가 만들었었던 Win32 서버에 대한 DataSnap .NET 클라이언트를

개발할 수 있습니다. 델파이 프리즘 2010 DataSnap 클라이언트를 작성하기 위해서는, 디자인 시점에

연결할 수 있도록 DataSnap 서버가 실행되어 있어야 합니다.

델파이 프리즘 2010을 시작하고, View | Server Explorer를 선택하여 델파이 프리즘 서버 익스플로러가

나타나도록 합니다. 실제로 DataSnap 서버와 동작하는지 확인하기 위해 여기에서 연결을 시도해봅니다.

서버 익스플로러는 트리뷰 형태의 창으로서, Data Connections라는 루트 노드를 가지고 있습니다. Data

Connections에서 오른쪽 마우스 클릭하여 “ Add Connection” 을 선택합니다. 아래와 같은

다이얼로그에서, Data sources 목록에서 DataSnap를 선택합니다(주의: datasource가 이미 선택되어

있다면 Change를 클릭해야 합니다).

향후 항상 DataSnap 데이터 커넥션만 사용하려 하지 않는 한, “ Always use this selection” 체크박스는

체크하지 않습니다.

“ Continue” 를 클릭하면 다이얼로그의 다음 페이지로 이동합니다. 여기에서, DataSnap 서버에

연결하기 위한 세부사항들을 지정할 수 있습니다. Protocol 드롭다운 콤보박스에서 tcp/ip 혹은 http를

선택합니다. 다음으로 Host를 지정해야 하며(DataSnap 서버가 실행되고 있는 컴퓨터 이름, 만약 동일한

로컬 컴퓨터에서 테스트하는 경우에는 localhost), 그리고 Port 번호를 지정해야 합니다. 포트 번호는

디폴트로 HTTP에 대해서는 Port 80, TCP/IP에 대해서는 Port 211 이지만, 앞에서부터 읽어왔다면 두 값이

달라질 수 있다는 것을 알 것입니다. ServerContainerUnitDemo 유닛의 트랜스포트 컴포넌트에서 지정한

값과 동일한 값으로 지정해야 합니다.

그 다음의 속성은 Path 입니다. 이 속성은 웹 브로커 기반의 DataSnap 서버에 연결하려는 경우에만

중요합니다 (DataSnap 웹 서버에 연결하기 위해 지정하는 URLPath로서, http://../ 도메인 부분의

뒷부분입니다.

마지막으로, DataSnap 서버가 HTTPAuthentication를 사용하는 경우, 인증 유저 이름과 패스워드를

지정하는 것을 잊지 마십시오.

45Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

Test Connection 버튼을 클릭하여 지정한 DataSnap 서버에 연결되는지 확인합니다. 만일 모든 것을

제대로 지정했다면 “ Test connection succeeded” 다이얼로그가 나타납니다.

OK를 클릭하면 데이터 커넥션 트리에 DataSnap 커넥션의 새로운 항목이 추가됩니다. 이 경우에는

localhost 노드에 나타날 것입니다. 새로운 노드를 확장하면 하위 노드로 테이블, 뷰와 저장 프로시저들이

나타날 것입니다. 테이블과 뷰는 비어 있겠지만 저장 프로시저에는 우리가 작성한 서버 메소드인

EchoString, GetEmployees와 ServerTime 등 DataSnap 서버에 있는 서버 매소드들 모두가 포함되어

있습니다.

46Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

서버 익스플로러에서 서버 메소드들을 테스트할 수 있습니다. 예를 들어, EchoString 메소드에서 오른쪽

마우스를 클릭하여 “ View Parameters” 를 선택해보십시오. 이렇게 하면 Value 파라미터의 값을 입력할

수 있는 새로운 창이 나타납니다. Value 파라마터의 값으로 42를 입력해보십시오. 이제 창에서 오른쪽

마우스를 클릭하고 “ Execute” 을 선택하여 DataSnap 서버의 EchoString 메소드를 실행합니다. 저장

프로시저 파라미터 창의 아래쪽에 결과가 나타날 것입니다.

47Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

EchoString으로 테스트해보는 것도 좋지만, GetEmployees 메소드로 Employees 테이블의 데이터를

가져오고 사용해보는 것이 좀 더 교육적일 것 같습니다. 이 저장 프로시저에는 파라미터가 없지만 역시

“ View Parameters” 명령을 선택할 수 있으며, 프로시저 파라미터가 빈 리스트로 표시됩니다. 다시 이

창에서 오른쪽 마우스를 클릭하여 “ Execute” 을 선택합니다. 이번에는, GetEmployees 메소드에서

리턴되는 Employees 테이블의 전체 레코드셋이 그 결과로 나옵니다.

48Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

7.1. WinForms 클라이언트

서버 익스플로러에서 DataSnap 서버 메소드를 작업하는 것이 흥미롭기는 하지만, 당연히 .NET

애플리케이션에서 서버 메소드를 호출하는 것이 실용적입니다. 마지막 예제로서, 델파이 프리즘에서 File |

New Project를 선택하여 New Project 위저드를 시작합니다. 그러면 생성 가능한 프로젝트 타겟들의

리스트를 보여줍니다.

왼쪽의 Project Types 리스트에서 Windows 프로젝트 타입을 선택하고 다시 Windows Application를

선택한 후, WindowsApplication1을 DataSnapClient로 이름을 변경합니다.

OK를 클릭하면, 델파이 프리즘 개발환경에 새로운 프로젝트 DataSnapClient가 생성되고 Main 폼으로

Main.pas 유닛이 추가되어 있습니다.

서버 익스플로러에서 우리가 앞 절에서 작성했던 DataSnap 서버에 대한 새 커넥션을 선택합니다.

Properties Explorer에 속성들이 나타날 것이며, 다음과 같은 값을 갖는 ConnectionString 속성도 나타날

것입니다.

communicationprotocol=http;hostname=localhost;port=8080;dsauthenticationuser=Bob;dsauthenticationpassword=Swart

데이터 커넥션 노드에서 오른쪽 마우스를 클릭하여 “ Generate Client Proxy” 옵션을 선택합니다.

이렇게 하면 TServerMethods1Client라는 클래스를 정의하는 ClientProxy1.pas 파일이 생성되고,

EchoString, ServerTime, GetEmployees 등의 메소드들이 포함됩니다. 다음은 클래스 정의 부분의

일부분입니다.

TServerMethods1Client = class public constructor (ADBXConnection: TAdoDbxConnection); constructor (ADBXConnection: TAdoDbxConnection; AInstanceOwner: Boolean); function EchoString(Value: string): string;

49Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

function ServerTime: DateTime; function GetEmployees: System.Data.IDataReader;

프록시 클래스와 별도로, 프로젝트의 레퍼런스 노드에 추가된 Borland.Data.AdoDbxClient와

Borland.Data.DbxClientDriver라는 레퍼런스들이 있습니다.

위의 TServerMethods1Client의 선언부에서 볼 수 있는 것처럼 이 클래스에는 두 개의 생성자가 있습니다.

둘 다 ADBXConnection 파라미터를 가지며, 두 번째 생성자는 AInstanceOwner이라는 boolean

파라미터를 추가로 가지고 있습니다. 이것은 인자를 사용하여 생성자를 호출해야 한다는 것을 의미합니다.

그러기 위해서는 프로젝트 설정을 수정해야 합니다. Solution Explorer의 DataSnapClient 노드에서 오른쪽

마우스 클릭하고 “ Properties” 를 선택합니다. 지금 보여지는 창에서 Compatibility 탭을 클릭하고

“ Allow Create constructor calls” 옵션을 체크합니다. 이 옵션은 new 연산자를 사용하는 대신 인자를

넘기면서 Create 생성자를 호출하는 것을 허용합니다.

이제 메인 폼으로 돌아와서 버튼 하나를 내려놓습니다. 버튼의 클릭 이벤트에서 DataSnap 서버에

연결하고 서버의 메소드들 중 하나를 호출 할 수 있습니다.

method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); var Client: ClientProxy1.TServerMethods1Client; Connection: Borland.Data.TAdoDbxDatasnapConnection; begin Connection := new Borland.Data.TAdoDbxDatasnapConnection(); Connection.ConnectionString := 'communicationprotocol=http;hostname=localhost;port=8080;dsauthenticationuser=Bob; dsauthenticationpassword=Swart'; Connection.Open; try Client := ClientProxy1.TServerMethods1Client.Create(Connection); MessageBox.Show(Client.EchoString('Delphi Prism 2010')); finally Connection.Close; end;

end;

50Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

그 결과는 아래에서 보이는 것처럼 ‘ Delphi Prism 2010’ 을 그대로 돌려줍니다.

비슷한 방법으로, GetEmployees 메소드를 호출하여 결과를 DataGridView에 할당합니다. 이것은 약간의

문제를 제기하는데, GetEmployees는 DataSet이나 DataTable이 아닌 IDataReader(TSQLDataSet에

해당)를 리턴하기 때문입니다. DataSet (Win32 측의 TClientDataSet와 비슷한 )안의 새 DataTable에

GetEmployees의 결과를 로드하는 코드 몇 줄을 작성해야 합니다.

method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); var Client: ClientProxy1.TServerMethods1Client; Connection: Borland.Data.TAdoDbxDatasnapConnection; Employees: System.Data.IDataReader; ds: System.Data.DataSet; dt: System.Data.DataTable; begin Connection := new Borland.Data.TAdoDbxDatasnapConnection(); Connection.ConnectionString := 'communicationprotocol=http;hostname=localhost;port=8080;dsauthenticationuser=Bob; dsauthenticationpassword=Swart'; Connection.Open; try Client := ClientProxy1.TServerMethods1Client.Create(Connection); Employees := Client.GetEmployees; ds := new DataSet(); dt := new DataTable("DataSnap"); ds.Tables.Add(dt); ds.Load(Employees, LoadOPtion.PreserveChanges, ds.Tables[0]); dataGridView1.DataSource := ds.Tables[0]; MessageBox.Show(Client.EchoString('Delphi Prism 2010')); finally Connection.Close; end;

end;

그 결과로 델파이 프리즘 WinForms 애플리케이션의 DataGridView에 아래와 같이 데이터가 나타나게

됩니다. 이로써 DataSnap 서버에 연결하는 가벼운(thin) .NET 클라이언트를 작성할 수 있다는 것을 보여

줍니다.

51Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

8. 요약

이 문서에서는, DataSnap으로 윈도우에서 GUI, 서비스 또는 콘솔 애플리케이션의 개발에 대해 알아보고,

웹에서는 CGI, ISAPI, 웹 디버거 애플리케이션 개발을 알아봤으며, Win32 및 .NET 클라이언트 개발에

대해서도 살펴봤습니다. 또한 DataSnap에서 TCP/IP, HTTP를 사용하는 방법과 HTTP 인증에 대해서도

알아봤으며, 필요한 경우 압축, 암호화 등을 위한 필터에 대해서도 알아봤습니다.

DataSnap 2010은 DataSnap 2009에 비해 상당히 확장되고 강화되었으며, COM 기반의 예전 버전의

DataSnap과 MIDAS 이후로 크게 개선되었습니다.

밥 슈워트 (Bob Swart) – 밥 슈워트 교육&컨설팅 (eBob42)

52Embarcadero Technologies / DEVGEAR

Delphi 2010의 새로운 DataSnap

Embarcadero Technologies / DEVGEAR

Embarcadero Technologies Inc.는 애플리케이션 개발자 및 데이터베이스 전문가가 자신이

선택한 환경에서 소프트웨어 애플리케이션을 설계, 빌드 및 실행하는 도구를 사용할 수 있도록

합니다. 전 세계 3백만 이상의 커뮤니티와 Fortune지 선정 100대 기업 중 90개 기업이

Embarcadero의 CodeGear™ 및 DatabaseGear™ 제품군을 기반으로 하여 생산성을

향상시키고 개방적인 협업 및 자유로운 혁신을 추구하고 있습니다. Embarcadero는 1993년에

설립되어 캘리포니아 샌프란시스코에 본사가 있으며 전 세계에 사무소를 두고 있습니다.

Embarcadero의 온라인 주소는 www.embarcadero.com입니다.

데브기어는 미국 Embarcadero Technologies Inc.와 기존의 코드기어 한국 지사의 협력으로

전략적으로 설립된 엠바카데로 솔루션 전문 공급 기업입니다. 데브기어는 Delphi, C++Builder,

JBuilder, Delphi Prism 등 개발툴 제품들과 ER/Studio, PowerSQL, DB Artisan, EA/Studio 등의

데이터베이스 툴 제품들에 대한 한국 시장에 공급은 물론 기술지원 및 교육을 제공합니다.

데브기어 웹 사이트는 http://www.devgear.co.kr/ 이며 제품에 대한 문의는

[email protected] 로 하면 됩니다.

Copyright © 2009 Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.

53

Delphi 2010의 새로운 DataSnap