Delphi的DataSnap用了一段时间了,但一直感觉有些地方还不够了解,所以花时间阅读了源代码,特作此烂笔头。
Datasnap是在之前的WebBorker基础上搭建的,DataSnap向导自动生成了基础的代码,所以就以基础代码为起点来看看DataSnap的内部机制。
首选创建一个 Stand-alone 的REST App, 向导至少会为我们生成一个Form1和一个WebModule1,
FormUnit1单元如下:
unit FormUnit1;
interface
uses
Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.AppEvnts, Vcl.StdCtrls, IdHTTPWebBrokerBridge, Web.HTTPApp;
type
TForm1 = class(TForm)
ButtonStart: TButton;
ButtonStop: TButton;
EditPort: TEdit;
Label1: TLabel;
ApplicationEvents1: TApplicationEvents;
ButtonOpenBrowser: TButton;
procedure FormCreate(Sender: TObject);
procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
procedure ButtonStartClick(Sender: TObject);
procedure ButtonStopClick(Sender: TObject);
procedure ButtonOpenBrowserClick(Sender: TObject);
private
FServer: TIdHTTPWebBrokerBridge;
procedure StartServer;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
WinApi.Windows, Winapi.ShellApi, Datasnap.DSSession;
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
ButtonStart.Enabled := not FServer.Active;
ButtonStop.Enabled := FServer.Active;
EditPort.Enabled := not FServer.Active;
end;
procedure TForm1.ButtonOpenBrowserClick(Sender: TObject);
var
LURL: string;
begin
StartServer;
LURL := Format('http://localhost:%s', [EditPort.Text]);
ShellExecute(0,
nil,
PChar(LURL), nil, nil, SW_SHOWNOACTIVATE);
end;
procedure TForm1.ButtonStartClick(Sender: TObject);
begin
StartServer;
end;
procedure TerminateThreads;
begin
if TDSSessionManager.Instance <> nil then
TDSSessionManager.Instance.TerminateAllSessions;
end;
procedure TForm1.ButtonStopClick(Sender: TObject);
begin
TerminateThreads;
FServer.Active := False;
FServer.Bindings.Clear;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FServer := TIdHTTPWebBrokerBridge.Create(Self);
end;
procedure TForm1.StartServer;
begin
if not FServer.Active then
begin
FServer.Bindings.Clear;
FServer.DefaultPort := StrToInt(EditPort.Text);
FServer.Active := True;
end;
end;
end.
在Form1中,有一个FServer ,ButtonStart.Click事件中有FServer.Active := True;
TIdHTTPWebBrokerBridge 是 TIdHTTPWebBrokerBridge = class(TIdCustomHTTPServer)
到目前上为,至少知道Datasanp是基于Id组件的,那么Id(idHttpServer)和WebModule, DSServer, DSHTTPWebDispatcher1 是如何关连上的,又是如何调用到
DDServerClass实例方法呢?
1 TIdHTTPWebBrokerBridge = class(TIdCustomHTTPServer) 2 private 3 procedure RunWebModuleClass(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; 4 AResponseInfo: TIdHTTPResponseInfo); 5 protected 6 FWebModuleClass: TComponentClass; 7 // 8 procedure DoCommandGet(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; 9 AResponseInfo: TIdHTTPResponseInfo); override; 10 procedure DoCommandOther(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; 11 AResponseInfo: TIdHTTPResponseInfo); override; 12 procedure InitComponent; override; 13 public 14 procedure RegisterWebModuleClass(AClass: TComponentClass); 15 end;
DoCommandGet的内部代码:
procedure TIdHTTPWebBrokerBridge.DoCommandGet(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); begin if FWebModuleClass <> nil then begin // FWebModuleClass, RegisterWebModuleClass supported for backward compatability RunWebModuleClass(AThread, ARequestInfo, AResponseInfo) end else begin {$IFDEF HAS_CLASSVARS} TIdHTTPWebBrokerBridgeRequestHandler.FWebRequestHandler.Run(AThread, ARequestInfo, AResponseInfo); {$ELSE} IndyWebRequestHandler.Run(AThread, ARequestInfo, AResponseInfo); {$ENDIF} end; end;
TIdHTTPWebBrokerBridgeRequestHandler的定义:
1 TIdHTTPWebBrokerBridgeRequestHandler = class(TWebRequestHandler) 2 {$IFDEF HAS_CLASSVARS} 3 private 4 class var FWebRequestHandler: TIdHTTPWebBrokerBridgeRequestHandler; 5 {$ENDIF} 6 public 7 constructor Create(AOwner: TComponent); override; 8 {$IFDEF HAS_CLASSVARS} 9 {$IFDEF HAS_CLASSDESTRUCTOR} 10 class destructor Destroy; 11 {$ENDIF} 12 {$ENDIF} 13 destructor Destroy; override; 14 procedure Run(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); 15 end;
第4行,静态的,唯一的。
第14行 就是TIdHTTPWebBrokerBridge.DoCommandGet中被调用的。
Run内部代码:
1 procedure TIdHTTPWebBrokerBridgeRequestHandler.Run(AThread: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); 2 var 3 LRequest: TIdHTTPAppRequest; 4 LResponse: TIdHTTPAppResponse; 5 begin 6 try 7 LRequest := TIdHTTPAppRequest.Create(AThread, ARequestInfo, AResponseInfo); 8 try 9 LResponse := TIdHTTPAppResponse.Create(LRequest, AThread, ARequestInfo, AResponseInfo); 10 try 11 // WebBroker will free it and we cannot change this behaviour 12 AResponseInfo.FreeContentStream := False; 13 HandleRequest(LRequest, LResponse); 14 finally 15 FreeAndNil(LResponse); 16 end; 17 finally 18 FreeAndNil(LRequest); 19 end; 20 except 21 // Let Indy handle this exception 22 raise; 23 end; 24 end;