读DataSnap源代码(一)

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;
时间: 2024-08-23 00:15:29

读DataSnap源代码(一)的相关文章

读DataSnap源代码(五)

1 function TDSHTTPWebDispatcher.DispatchRequest(Sender: TObject; 2 Request: TWebRequest; Response: TWebResponse): Boolean; 3 begin 4 try 5 if Owner is TWebModule then 6 DataSnapWebModule := TWebModule(Owner); 7 try 8 try 9 RequiresServer; 10 TDSHTTPS

读DataSnap源代码(二)

program Project1; {$APPTYPE GUI} {$R *.dres} uses Vcl.Forms, Web.WebReq, IdHTTPWebBrokerBridge, FormUnit1 in 'FormUnit1.pas' {Form1}, ServerMethodsUnit1 in 'ServerMethodsUnit1.pas', WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule}; {$R

读DataSnap源代码(三)

1 function TWebRequestHandler.HandleRequest(Request: TWebRequest; 2 Response: TWebResponse): Boolean; 3 var 4 I: Integer; 5 LWebModule: TComponent; 6 LWebAppServices: IWebAppServices; 7 LGetWebAppServices: IGetWebAppServices; 8 LComponent: TComponent

读DataSnap源代码(四)

继续篇中的 1 function TCustomWebDispatcher.DispatchAction(Request: TWebRequest; 2 Response: TWebResponse): Boolean; 3 var 4 I: Integer; 5 Action, Default: TWebActionItem; 6 Dispatch: IWebDispatch; 7 begin 8 FRequest := Request; 9 FResponse := Response; 10

最近读cocoaui源代码有感

上半年为了做一个ios的应用,引入了cocoaui库,主要是用来布局ios界面,发现简化了不少代码和工作量.因为在写第一个ios应用的时候,用的代码布局,在适配4s和6的机型时候,几乎被搞死,大量的约束定义充斥在代码中,惨不忍睹. cocoaui的作者是ssdb的作者ideawu,在微博里面比较活跃,有问题at他一般很快就会有回应.ssdb是一个类似于redis的nosql数据库:像这样一个在客户端和服务器领域都有建树的人还是很少的.我等普普通通的程序员,距离这种大神还是有一些距离,不过不能气馁

MYSQL 源代码 编译原理 AST和解析树 代码语法解析

MYSQL 源代码 编译原理 AST和解析树 代码语法解析 http://blog.csdn.net/wfp458113181wfp/article/details/17082355 使用AST树 分类:             antlr              2013-12-02 22:39     255人阅读     评论(0)     收藏     举报 目录(?)[+] 第五章使用AST树中间结果来计算表达式值 创建ASTS 第五章.使用AST树中间结果来计算表达式值 现在我们已

【JUnit4.10源代码分析】6.1 排序和过滤

abstract class ParentRunner<T> extends Runner implements Filterable,Sortable 本节介绍排序和过滤.(虽然JUnit4.8.2源代码分析-6.1 排序和过滤中演示了客户使用排序和过滤的方式,也有些不明白其设计意图,但是,先读懂源代码为妙.说不定看着看着就明白了.) org.junit.runner.manipulation包 排序和过滤的相关类型,在org.junit.runner.manipulation包中. 1.例

UNIX和Linux之间有什么关系?

1.UNIX和Linux之间有什么关系? 答:1969年UNIX诞生于Bell实验室,是一种多用户多任务操作系统.最早是用汇编语言写的,之后用C语言重写.UNIX对硬件依赖性强,是一种非开源的商业操作系统. Linux是1991年一个芬兰研究生Linus写的一个类UNIX操作系统,Linux一出现就表现出强大的生命力,它可以运行在多种硬件平台上.后来Linus把源码公布出来,得到了很多人的支持,逐渐成为了基于GPL协议的GNU自由软件,免费且开源发展迅速. 2.BSD是什么? 我们通常说的Fre

linux历史 作业

1.Unix 和 Linux之间有什么关系? Linux是一种类Unix系统,可以说Linux是由Unix系统衍生过来的. PS:1) UNIX系统大多是与硬件配套的,而Linux则可运行在多种硬件平台上. 2) UNIX是商业软件,而Linux是自由软件,免费.公开源代码的.[UNIX(5万美圆)而Linux免费] Unix的历史久于linux. Linux的思想源于Unix 2. BSD是什么? 我们通常说的FreeBSD.NetBSD和BSD又有什么关系呢? 柏克莱软件套件(英语:Berk