mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Refactoring to:
* Enable working with listeners in a DI context. * Class Changes to provide a better understanding of the functionality; * Removal singletons variables (not the framework that must manage it); * README update;
This commit is contained in:
parent
0d0d2d7aad
commit
04b83cc0f5
118
README.md
118
README.md
@ -185,102 +185,86 @@ Now you have a performant RESTful server wich respond to the following URLs:
|
||||
|
||||
###Quick Creation of DelphiMVCFramework Server
|
||||
|
||||
If you dont plan to deploy your DMVCFramework server behind a webserver (apache or IIS) you can also pack more than one server into one single executable. In this case, the process is a bit different and involves the creation of a server container. However, create a new server is a simple task:
|
||||
If you dont plan to deploy your DMVCFramework server behind a webserver (apache or IIS) you can also pack more than one listener application server into one single executable. In this case, the process is a bit different and involves the creation of a listener context. However, create a new server is a simple task:
|
||||
|
||||
```delphi
|
||||
uses
|
||||
MVCFramework.Server;
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl;
|
||||
|
||||
var
|
||||
ServerInfo: IMVCServerInfo;
|
||||
Server: IMVCServer;
|
||||
LServerListener: IMVCListener;
|
||||
begin
|
||||
ServerInfo := TMVCServerInfoFactory.Build;
|
||||
ServerInfo.ServerName := 'MVCServer';
|
||||
ServerInfo.Port := 4000;
|
||||
ServerInfo.MaxConnections := 1000;
|
||||
//You must reference your TWebModuleClass
|
||||
ServerInfo.WebModuleClass := YourServerWebModuleClass;
|
||||
LServerListener := TMVCListener.Create(TMVCListenerProperties.New
|
||||
.SetName('Listener1')
|
||||
.SetPort(5000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(YourServerWebModuleClass)
|
||||
);
|
||||
|
||||
Server := TMVCServerFactory.Build(ServerInfo);
|
||||
Server.Start;
|
||||
Server.Stop;
|
||||
LServerListener.Start;
|
||||
LServerListener.Stop;
|
||||
end;
|
||||
```
|
||||
|
||||
If you want to add a layer of security:
|
||||
If you want to add a layer of security (in its WebModule you should add the security middleware):
|
||||
|
||||
```delphi
|
||||
uses
|
||||
MVCFramework.Server;
|
||||
|
||||
var
|
||||
ServerInfo: IMVCServerInfo;
|
||||
Server: IMVCServer;
|
||||
OnAuthentication: TMVCAuthenticationDelegate;
|
||||
begin
|
||||
ServerInfo := TMVCServerInfoFactory.Build;
|
||||
ServerInfo.ServerName := 'MVCServer';
|
||||
ServerInfo.Port := 4000;
|
||||
ServerInfo.MaxConnections := 1000;
|
||||
//You must reference your TWebModuleClass
|
||||
ServerInfo.WebModuleClass := YourServerWebModuleClass;
|
||||
|
||||
OnAuthentication := procedure(const pUserName, pPassword: string; pUserRoles: TList<string>; var pIsValid: Boolean)
|
||||
begin
|
||||
pIsValid := pUserName.Equals('dmvc') and pPassword.Equals('123');
|
||||
end;
|
||||
|
||||
ServerInfo.Security := TMVCDefaultSecurity.Create(OnAuthentication, nil);
|
||||
|
||||
Server := TMVCServerFactory.Build(ServerInfo);
|
||||
Server.Start;
|
||||
end;
|
||||
|
||||
//And in his WebModule you should add the security middleware
|
||||
uses
|
||||
MVCFramework.Middleware.Authentication;
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl,
|
||||
MVCFramework.Middleware.Authentication;
|
||||
|
||||
procedure TTestWebModule.WebModuleCreate(Sender: TObject);
|
||||
begin
|
||||
MVCEngine := TMVCEngine.Create(Self);
|
||||
FMVCEngine := TMVCEngine.Create(Self);
|
||||
|
||||
// Add Yours Controllers
|
||||
MVCEngine.AddController(TYourController);
|
||||
// Add Yours Controllers
|
||||
FMVCEngine.AddController(TYourController);
|
||||
|
||||
// Add Security Middleware
|
||||
MVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(Server.Info.Security));
|
||||
// Add Security Middleware
|
||||
FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(
|
||||
TMVCDefaultAuthenticationHandler.New
|
||||
.SetOnAuthentication(
|
||||
procedure(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var IsValid: Boolean;
|
||||
const ASessionData: TDictionary<String, String>)
|
||||
begin
|
||||
IsValid := AUserName.Equals('dmvc') and APassword.Equals('123');
|
||||
end
|
||||
)
|
||||
));
|
||||
end;
|
||||
```
|
||||
|
||||
You can work with a container of DelphiMVCFramework servers:
|
||||
In stand alone mode you can work with a context that supports multiple listeners servers:
|
||||
|
||||
```delphi
|
||||
uses
|
||||
MVCFramework.Server;
|
||||
uses
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl;
|
||||
|
||||
var
|
||||
ServerOneInfo: IMVCServerInfo;
|
||||
ServerTwoInfo: IMVCServerInfo;
|
||||
Container: IMVCServerContainer;
|
||||
LServerListenerCtx: IMVCListenersContext;
|
||||
|
||||
begin
|
||||
Container := TMVCServerContainerFactory.Build();
|
||||
LServerListenerCtx := TMVCListenersContext.Create;
|
||||
|
||||
ServerOneInfo := TMVCServerInfoFactory.Build;
|
||||
ServerOneInfo.ServerName := 'MVCServer1';
|
||||
ServerOneInfo.Port := 4000;
|
||||
ServerOneInfo.MaxConnections := 1000;
|
||||
ServerOneInfo.WebModuleClass := ServerOneWebModuleClass;
|
||||
LServerListenerCtx.Add(TMVCListenerProperties.New
|
||||
.SetName('Listener1')
|
||||
.SetPort(6000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(WebModuleClass1)
|
||||
);
|
||||
|
||||
Container.CreateServer(ServerOneInfo);
|
||||
LServerListenerCtx.Add(TMVCListenerProperties.New
|
||||
.SetName('Listener2')
|
||||
.SetPort(7000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(WebModuleClass2)
|
||||
);
|
||||
|
||||
ServerTwoInfo := TMVCServerInfoFactory.Build;
|
||||
ServerTwoInfo.ServerName := 'MVCServer2';
|
||||
ServerTwoInfo.Port := 5000;
|
||||
ServerTwoInfo.MaxConnections := 1000;
|
||||
ServerTwoInfo.WebModuleClass := ServerTwoWebModuleClass;
|
||||
Container.CreateServer(ServerTwoInfo);
|
||||
Container.StartServers();
|
||||
LServerListenerCtx.StartAll;
|
||||
end;
|
||||
```
|
||||
|
||||
|
@ -9,6 +9,7 @@ uses
|
||||
Web.WebReq,
|
||||
Web.WebBroker,
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl,
|
||||
WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule} ,
|
||||
App1MainControllerU in 'App1MainControllerU.pas';
|
||||
|
||||
@ -16,21 +17,23 @@ uses
|
||||
|
||||
procedure RunServer(APort: Integer);
|
||||
var
|
||||
LServerInfo: IMVCServerInfo;
|
||||
LServerListenerCtx: IMVCListenersContext;
|
||||
LInputRecord: TInputRecord;
|
||||
LEvent: DWord;
|
||||
LHandle: THandle;
|
||||
begin
|
||||
Writeln(Format('Starting HTTP Server or port %d', [APort]));
|
||||
|
||||
LServerInfo := TMVCServerInfoFactory.Build;
|
||||
LServerInfo.ServerName := 'BasicDemo';
|
||||
LServerInfo.Port := APort;
|
||||
LServerInfo.MaxConnections := 1024;
|
||||
LServerInfo.WebModuleClass := WebModuleClass;
|
||||
LServerListenerCtx := TMVCListenersContext.Create;
|
||||
|
||||
MVCServerDefault.Container.CreateServer(LServerInfo);
|
||||
MVCServerDefault.Container.StartServers;
|
||||
LServerListenerCtx.Add(TMVCListenerProperties.New
|
||||
.SetName('BasicDemo')
|
||||
.SetPort(APort)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(WebModuleClass)
|
||||
);
|
||||
|
||||
LServerListenerCtx.StartAll;
|
||||
|
||||
ShellExecute(0, 'open', pChar('http://localhost:' + inttostr(APort) +
|
||||
'/div/10/20'), nil, nil, SW_SHOWMAXIMIZED);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{7B54055A-5749-4136-9FE2-35FDBEEA874C}</ProjectGuid>
|
||||
<ProjectVersion>15.4</ProjectVersion>
|
||||
<ProjectVersion>16.1</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>BasicDemo.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
|
Binary file not shown.
@ -2,19 +2,19 @@ unit WebModuleUnit1;
|
||||
|
||||
interface
|
||||
|
||||
uses System.SysUtils,
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
Web.HTTPApp,
|
||||
MVCFramework;
|
||||
|
||||
type
|
||||
|
||||
TWebModule1 = class(TWebModule)
|
||||
procedure WebModuleCreate(Sender: TObject);
|
||||
procedure WebModuleDestroy(Sender: TObject);
|
||||
|
||||
private
|
||||
MVC: TMVCEngine;
|
||||
|
||||
FMVCEngine: TMVCEngine;
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
@ -26,19 +26,20 @@ implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
uses App1MainControllerU;
|
||||
uses
|
||||
App1MainControllerU;
|
||||
|
||||
procedure TWebModule1.WebModuleCreate(Sender: TObject);
|
||||
begin
|
||||
MVC := TMVCEngine.Create(Self);
|
||||
MVC.Config['view_path'] := '..\Debug\HTML5Application';
|
||||
MVC.Config['document_root'] := 'HTML5Application\public_html';
|
||||
MVC.AddController(TApp1MainController);
|
||||
FMVCEngine := TMVCEngine.Create(Self);
|
||||
FMVCEngine.Config['view_path'] := '..\Debug\HTML5Application';
|
||||
FMVCEngine.Config['document_root'] := 'HTML5Application\public_html';
|
||||
FMVCEngine.AddController(TApp1MainController);
|
||||
end;
|
||||
|
||||
procedure TWebModule1.WebModuleDestroy(Sender: TObject);
|
||||
begin
|
||||
MVC.free;
|
||||
FMVCEngine.free;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
350
sources/MVCFramework.Server.Impl.pas
Normal file
350
sources/MVCFramework.Server.Impl.pas
Normal file
@ -0,0 +1,350 @@
|
||||
unit MVCFramework.Server.Impl;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
|
||||
{$IFDEF IOCP}
|
||||
|
||||
Iocp.DSHTTPWebBroker
|
||||
|
||||
{$ELSE}
|
||||
|
||||
IdHTTPWebBrokerBridge
|
||||
|
||||
{$ENDIF},
|
||||
|
||||
MVCFramework.Server;
|
||||
|
||||
type
|
||||
|
||||
TMVCListenerProperties = class(TInterfacedObject, IMVCListenerProperties)
|
||||
private
|
||||
FName: string;
|
||||
FPort: Integer;
|
||||
FMaxConnections: Integer;
|
||||
FWebModuleClass: TComponentClass;
|
||||
protected
|
||||
function GetName: string;
|
||||
function SetName(const AValue: string): IMVCListenerProperties;
|
||||
|
||||
function GetPort: Integer;
|
||||
function SetPort(AValue: Integer): IMVCListenerProperties;
|
||||
|
||||
function GetMaxConnections: Integer;
|
||||
function SetMaxConnections(AValue: Integer): IMVCListenerProperties;
|
||||
|
||||
function GetWebModuleClass: TComponentClass;
|
||||
function SetWebModuleClass(AValue: TComponentClass): IMVCListenerProperties;
|
||||
public
|
||||
constructor Create;
|
||||
class function New: IMVCListenerProperties; static;
|
||||
end;
|
||||
|
||||
TMVCListener = class(TInterfacedObject, IMVCListener)
|
||||
private
|
||||
|
||||
{$IFDEF IOCP}
|
||||
|
||||
FBridge: TIocpWebBrokerBridge;
|
||||
|
||||
{$ELSE}
|
||||
|
||||
FBridge: TIdHTTPWebBrokerBridge;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
protected
|
||||
function GetActive: Boolean;
|
||||
|
||||
procedure Start;
|
||||
procedure Stop;
|
||||
public
|
||||
constructor Create(AProperties: IMVCListenerProperties);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TMVCListenersContext = class(TInterfacedObject, IMVCListenersContext)
|
||||
private
|
||||
FListeners: TDictionary<string, IMVCListener>;
|
||||
protected
|
||||
function Add(const AName: string; AListener: IMVCListener): IMVCListenersContext; overload;
|
||||
function Add(AProperties: IMVCListenerProperties): IMVCListenersContext; overload;
|
||||
function Remove(const AListenerName: string): IMVCListenersContext;
|
||||
|
||||
procedure StartAll;
|
||||
procedure StopAll;
|
||||
|
||||
function FindByName(const AListenerName: string): IMVCListener;
|
||||
|
||||
procedure ForEach(AProc: TProc<string, IMVCListener>);
|
||||
function Count: Integer;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TMVCDefaultAuthenticationHandler = class(TInterfacedObject, IMVCDefaultAuthenticationHandler)
|
||||
private
|
||||
FRequestDelegate: TMVCRequestDelegate;
|
||||
FAuthenticationDelegate: TMVCAuthenticationDelegate;
|
||||
FAuthorizationDelegate: TMVCAuthorizationDelegate;
|
||||
protected
|
||||
procedure OnRequest(const AControllerQualifiedClassName, AActionName: string; var AAuthenticationRequired: Boolean);
|
||||
|
||||
procedure OnAuthentication(const AUserName, APassword: string; AUserRoles: TList<string>; var IsValid: Boolean;
|
||||
const ASessionData: TDictionary<String, String>);
|
||||
|
||||
procedure OnAuthorization(AUserRoles: TList<string>; const AControllerQualifiedClassName: string; const AActionName: string;
|
||||
var IsAuthorized: Boolean);
|
||||
public
|
||||
class function New: IMVCDefaultAuthenticationHandler; static;
|
||||
|
||||
function SetOnRequest(AMethod: TMVCRequestDelegate): IMVCDefaultAuthenticationHandler;
|
||||
function SetOnAuthentication(AMethod: TMVCAuthenticationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
function SetOnAuthorization(AMethod: TMVCAuthorizationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMVCListenerProperties }
|
||||
|
||||
constructor TMVCListenerProperties.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FName := '';
|
||||
FPort := 8080;
|
||||
FMaxConnections := 1024;
|
||||
FWebModuleClass := nil;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.GetMaxConnections: Integer;
|
||||
begin
|
||||
Result := FMaxConnections;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.GetName: string;
|
||||
begin
|
||||
Result := FName;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.GetPort: Integer;
|
||||
begin
|
||||
Result := FPort;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.GetWebModuleClass: TComponentClass;
|
||||
begin
|
||||
Result := FWebModuleClass;
|
||||
end;
|
||||
|
||||
class function TMVCListenerProperties.New: IMVCListenerProperties;
|
||||
begin
|
||||
Result := TMVCListenerProperties.Create;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.SetMaxConnections(AValue: Integer): IMVCListenerProperties;
|
||||
begin
|
||||
FMaxConnections := AValue;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.SetName(const AValue: string): IMVCListenerProperties;
|
||||
begin
|
||||
FName := AValue;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.SetPort(AValue: Integer): IMVCListenerProperties;
|
||||
begin
|
||||
FPort := AValue;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCListenerProperties.SetWebModuleClass(AValue: TComponentClass): IMVCListenerProperties;
|
||||
begin
|
||||
FWebModuleClass := AValue;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
{ TMVCListener }
|
||||
|
||||
constructor TMVCListener.Create(AProperties: IMVCListenerProperties);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
if not Assigned(AProperties) then
|
||||
raise EMVCServerException.Create('Listener properties was not informed.');
|
||||
|
||||
if AProperties.GetName.IsEmpty then
|
||||
raise EMVCServerException.Create('Listener name was not informed.');
|
||||
|
||||
{$IFDEF IOCP}
|
||||
|
||||
FBridge := TIocpWebBrokerBridge.Create(nil);
|
||||
FBridge.Port := AProperties.GetPort;
|
||||
FBridge.MaxClients := AProperties.GetMaxConnections;
|
||||
FBridge.RegisterWebModuleClass(AProperties.GetWebModuleClass);
|
||||
|
||||
{$ELSE}
|
||||
|
||||
FBridge := TIdHTTPWebBrokerBridge.Create(nil);
|
||||
FBridge.DefaultPort := AProperties.GetPort;
|
||||
FBridge.MaxConnections := AProperties.GetMaxConnections;
|
||||
FBridge.RegisterWebModuleClass(AProperties.GetWebModuleClass);
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
end;
|
||||
|
||||
destructor TMVCListener.Destroy;
|
||||
begin
|
||||
if Assigned(FBridge) then
|
||||
FBridge.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TMVCListener.GetActive: Boolean;
|
||||
begin
|
||||
Result := FBridge.Active;
|
||||
end;
|
||||
|
||||
procedure TMVCListener.Start;
|
||||
begin
|
||||
FBridge.Active := True;
|
||||
end;
|
||||
|
||||
procedure TMVCListener.Stop;
|
||||
begin
|
||||
FBridge.Active := False;
|
||||
end;
|
||||
|
||||
{ TMVCListenersContext }
|
||||
|
||||
function TMVCListenersContext.Add(const AName: string; AListener: IMVCListener): IMVCListenersContext;
|
||||
begin
|
||||
FListeners.AddOrSetValue(AName, AListener);
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCListenersContext.Add(AProperties: IMVCListenerProperties): IMVCListenersContext;
|
||||
var
|
||||
Listener: IMVCListener;
|
||||
begin
|
||||
Listener := TMVCListener.Create(AProperties);
|
||||
Result := Add(AProperties.GetName, Listener);
|
||||
end;
|
||||
|
||||
function TMVCListenersContext.Count: Integer;
|
||||
begin
|
||||
Result := FListeners.Count;
|
||||
end;
|
||||
|
||||
constructor TMVCListenersContext.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FListeners := TDictionary<string, IMVCListener>.Create;
|
||||
end;
|
||||
|
||||
destructor TMVCListenersContext.Destroy;
|
||||
begin
|
||||
StopAll;
|
||||
FListeners.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TMVCListenersContext.FindByName(const AListenerName: string): IMVCListener;
|
||||
begin
|
||||
Result := FListeners.Items[AListenerName];
|
||||
end;
|
||||
|
||||
procedure TMVCListenersContext.ForEach(AProc: TProc<string, IMVCListener>);
|
||||
var
|
||||
Pair: TPair<string, IMVCListener>;
|
||||
begin
|
||||
for Pair in FListeners do
|
||||
AProc(Pair.Key, Pair.Value);
|
||||
end;
|
||||
|
||||
function TMVCListenersContext.Remove(const AListenerName: string): IMVCListenersContext;
|
||||
begin
|
||||
if (FListeners.ContainsKey(AListenerName)) then
|
||||
FListeners.Remove(AListenerName)
|
||||
else
|
||||
raise EMVCServerException.Create('Listener ' + AListenerName + ' not found.');
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
procedure TMVCListenersContext.StartAll;
|
||||
begin
|
||||
ForEach(
|
||||
procedure(AName: string; AListener: IMVCListener)
|
||||
begin
|
||||
AListener.Start;
|
||||
end
|
||||
);
|
||||
end;
|
||||
|
||||
procedure TMVCListenersContext.StopAll;
|
||||
begin
|
||||
ForEach(
|
||||
procedure(AName: string; AListener: IMVCListener)
|
||||
begin
|
||||
AListener.Stop;
|
||||
end
|
||||
);
|
||||
end;
|
||||
|
||||
{ TMVCDefaultAuthenticationHandler }
|
||||
|
||||
class function TMVCDefaultAuthenticationHandler.New: IMVCDefaultAuthenticationHandler;
|
||||
begin
|
||||
Result := TMVCDefaultAuthenticationHandler.Create;
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultAuthenticationHandler.OnAuthentication(const AUserName, APassword: string; AUserRoles: TList<string>;
|
||||
var IsValid: Boolean; const ASessionData: TDictionary<String, String>);
|
||||
begin
|
||||
IsValid := True;
|
||||
if Assigned(FAuthenticationDelegate) then
|
||||
FAuthenticationDelegate(AUserName, APassword, AUserRoles, IsValid, ASessionData);
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultAuthenticationHandler.OnAuthorization(AUserRoles: TList<string>; const AControllerQualifiedClassName,
|
||||
AActionName: string; var IsAuthorized: Boolean);
|
||||
begin
|
||||
IsAuthorized := True;
|
||||
if Assigned(FAuthorizationDelegate) then
|
||||
FAuthorizationDelegate(AUserRoles, AControllerQualifiedClassName, AActionName, IsAuthorized);
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultAuthenticationHandler.OnRequest(const AControllerQualifiedClassName, AActionName: string;
|
||||
var AAuthenticationRequired: Boolean);
|
||||
begin
|
||||
AAuthenticationRequired := True;
|
||||
if Assigned(FRequestDelegate) then
|
||||
FRequestDelegate(AControllerQualifiedClassName, AActionName, AAuthenticationRequired);
|
||||
end;
|
||||
|
||||
function TMVCDefaultAuthenticationHandler.SetOnAuthentication(AMethod: TMVCAuthenticationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
begin
|
||||
FAuthenticationDelegate := AMethod;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCDefaultAuthenticationHandler.SetOnAuthorization(AMethod: TMVCAuthorizationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
begin
|
||||
FAuthorizationDelegate := AMethod;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMVCDefaultAuthenticationHandler.SetOnRequest(AMethod: TMVCRequestDelegate): IMVCDefaultAuthenticationHandler;
|
||||
begin
|
||||
FRequestDelegate := AMethod;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
end.
|
@ -1,604 +1,73 @@
|
||||
{***************************************************************************}
|
||||
{ }
|
||||
{ Delphi MVC Framework }
|
||||
{ }
|
||||
{ Copyright (c) 2010-2015 Daniele Teti and the DMVCFramework Team }
|
||||
{ }
|
||||
{ https://github.com/danieleteti/delphimvcframework }
|
||||
{ }
|
||||
{***************************************************************************}
|
||||
{ }
|
||||
{ Licensed under the Apache License, Version 2.0 (the "License"); }
|
||||
{ you may not use this file except in compliance with the License. }
|
||||
{ You may obtain a copy of the License at }
|
||||
{ }
|
||||
{ http://www.apache.org/licenses/LICENSE-2.0 }
|
||||
{ }
|
||||
{ Unless required by applicable law or agreed to in writing, software }
|
||||
{ distributed under the License is distributed on an "AS IS" BASIS, }
|
||||
{ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
|
||||
{ See the License for the specific language governing permissions and }
|
||||
{ limitations under the License. }
|
||||
{ }
|
||||
{***************************************************************************}
|
||||
|
||||
unit MVCFramework.Server;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
System.SyncObjs,
|
||||
System.Classes
|
||||
|
||||
{$IFDEF IOCP},
|
||||
|
||||
Iocp.DSHTTPWebBroker
|
||||
|
||||
{$ELSE},
|
||||
|
||||
IdHTTPWebBrokerBridge
|
||||
|
||||
{$ENDIF},
|
||||
|
||||
MVCFramework.Commons;
|
||||
|
||||
type
|
||||
|
||||
EMVCServerException = class(Exception);
|
||||
|
||||
IMVCSecurity = MVCFramework.Commons.IMVCAuthenticationHandler;
|
||||
IMVCListenerProperties = interface
|
||||
['{82721C88-A308-4B2E-B94A-8E7CEEC4721F}']
|
||||
function GetName: string;
|
||||
function SetName(const AValue: string): IMVCListenerProperties;
|
||||
|
||||
TMVCBaseSecurity = class abstract(TInterfacedObject)
|
||||
strict private
|
||||
{ private declarations }
|
||||
strict protected
|
||||
{ protected declarations }
|
||||
public
|
||||
{ public declarations }
|
||||
function GetPort: Integer;
|
||||
function SetPort(AValue: Integer): IMVCListenerProperties;
|
||||
|
||||
function GetMaxConnections: Integer;
|
||||
function SetMaxConnections(AValue: Integer): IMVCListenerProperties;
|
||||
|
||||
function GetWebModuleClass: TComponentClass;
|
||||
function SetWebModuleClass(AValue: TComponentClass): IMVCListenerProperties;
|
||||
end;
|
||||
|
||||
TMVCAuthenticationDelegate = reference to procedure(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var AIsValid: Boolean; const ASessionData: TDictionary<String, String>);
|
||||
IMVCListener = interface
|
||||
['{127A5E5D-D968-4409-BE9A-8D3AE08E6009}']
|
||||
function GetActive: Boolean;
|
||||
|
||||
TMVCAuthorizationDelegate = reference to procedure(AUserRoles: TList<string>;
|
||||
const AControllerQualifiedClassName: string; const AActionName: string; var AIsAuthorized: Boolean);
|
||||
|
||||
TMVCDefaultSecurity = class(TMVCBaseSecurity, IMVCSecurity)
|
||||
strict private
|
||||
FAuthenticationDelegate: TMVCAuthenticationDelegate;
|
||||
FAuthorizationDelegate: TMVCAuthorizationDelegate;
|
||||
public
|
||||
constructor Create(AAuthenticationDelegate: TMVCAuthenticationDelegate;
|
||||
AAuthorizationDelegate: TMVCAuthorizationDelegate);
|
||||
|
||||
procedure OnRequest(const AControllerQualifiedClassName, AActionName: string;
|
||||
var AAuthenticationRequired: Boolean);
|
||||
|
||||
procedure OnAuthentication(const AUserName, APassword: string; AUserRoles: TList<string>;
|
||||
var AIsValid: Boolean; const ASessionData: TDictionary<String, String>);
|
||||
|
||||
procedure OnAuthorization(AUserRoles: TList<string>; const AControllerQualifiedClassName: string;
|
||||
const AActionName: string; var AIsAuthorized: Boolean);
|
||||
end;
|
||||
|
||||
IMVCServerInfo = interface
|
||||
['{3A328987-2485-4660-BB9B-B8AFFF47E4BA}']
|
||||
function GetServerName(): string;
|
||||
procedure SetServerName(const AValue: string);
|
||||
|
||||
function GetPort(): Integer;
|
||||
procedure SetPort(const AValue: Integer);
|
||||
|
||||
function GetMaxConnections(): Integer;
|
||||
procedure SetMaxConnections(const AValue: Integer);
|
||||
|
||||
function GetWebModuleClass(): TComponentClass;
|
||||
procedure SetWebModuleClass(AValue: TComponentClass);
|
||||
|
||||
function GetSecurity(): IMVCSecurity;
|
||||
procedure SetSecurity(AValue: IMVCSecurity);
|
||||
|
||||
property ServerName: string read GetServerName write SetServerName;
|
||||
property Port: Integer read GetPort write SetPort;
|
||||
property MaxConnections: Integer read GetMaxConnections write SetMaxConnections;
|
||||
property WebModuleClass: TComponentClass read GetWebModuleClass write SetWebModuleClass;
|
||||
property Security: IMVCSecurity read GetSecurity write SetSecurity;
|
||||
end;
|
||||
|
||||
TMVCServerInfoFactory = class sealed
|
||||
strict private
|
||||
|
||||
{$HINTS OFF}
|
||||
|
||||
constructor Create;
|
||||
|
||||
{$HINTS ON}
|
||||
|
||||
public
|
||||
class function Build(): IMVCServerInfo; static;
|
||||
end;
|
||||
|
||||
IMVCServer = interface
|
||||
['{95E91DF0-6ABF-46B1-B995-FC748BC54568}']
|
||||
function GetActive(): Boolean;
|
||||
function GetInfo(): IMVCServerInfo;
|
||||
|
||||
procedure Start();
|
||||
procedure Stop();
|
||||
procedure Start;
|
||||
procedure Stop;
|
||||
|
||||
property Active: Boolean read GetActive;
|
||||
property Info: IMVCServerInfo read GetInfo;
|
||||
end;
|
||||
|
||||
TMVCServerFactory = class sealed
|
||||
strict private
|
||||
IMVCListenersContext = interface
|
||||
['{9EA6BBDB-B5C1-462E-BBF4-AA30A4317F54}']
|
||||
function Add(const AName: string; AListener: IMVCListener): IMVCListenersContext; overload;
|
||||
function Add(AProperties: IMVCListenerProperties): IMVCListenersContext; overload;
|
||||
function Remove(const AListenerName: string): IMVCListenersContext;
|
||||
|
||||
{$HINTS OFF}
|
||||
procedure StartAll;
|
||||
procedure StopAll;
|
||||
|
||||
constructor Create;
|
||||
function FindByName(const AListenerName: string): IMVCListener;
|
||||
|
||||
{$HINTS ON}
|
||||
|
||||
public
|
||||
class function Build(AServerInfo: IMVCServerInfo): IMVCServer; static;
|
||||
procedure ForEach(AProc: TProc<string, IMVCListener>);
|
||||
function Count: Integer;
|
||||
end;
|
||||
|
||||
IMVCServerContainer = interface
|
||||
['{B20796A0-CB07-4D16-BEAB-4F0B10880318}']
|
||||
function GetServers(): TDictionary<string, IMVCServer>;
|
||||
TMVCRequestDelegate = reference to procedure(const AControllerQualifiedClassName, AActionName: string;
|
||||
var AAuthenticationRequired: Boolean);
|
||||
|
||||
procedure CreateServer(AServerInfo: IMVCServerInfo);
|
||||
procedure DestroyServer(const AServerName: string);
|
||||
TMVCAuthenticationDelegate = reference to procedure(const AUserName, APassword: string; AUserRoles: TList<string>;
|
||||
var IsValid: Boolean; const ASessionData: TDictionary<String, String>);
|
||||
|
||||
procedure StartServers();
|
||||
procedure StopServers();
|
||||
TMVCAuthorizationDelegate = reference to procedure(AUserRoles: TList<string>; const AControllerQualifiedClassName: string;
|
||||
const AActionName: string; var IsAuthorized: Boolean);
|
||||
|
||||
function FindServerByName(const AServerName: string): IMVCServer;
|
||||
|
||||
property Servers: TDictionary<string, IMVCServer> read GetServers;
|
||||
end;
|
||||
|
||||
TMVCServerContainerFactory = class sealed
|
||||
strict private
|
||||
|
||||
{$HINTS OFF}
|
||||
|
||||
constructor Create;
|
||||
|
||||
{$HINTS ON}
|
||||
|
||||
public
|
||||
class function Build(): IMVCServerContainer; static;
|
||||
end;
|
||||
|
||||
MVCServerDefault = class sealed
|
||||
strict private
|
||||
|
||||
{$HINTS OFF}
|
||||
|
||||
constructor Create;
|
||||
|
||||
{$HINTS ON}
|
||||
|
||||
public
|
||||
class function Container(): IMVCServerContainer; static;
|
||||
IMVCDefaultAuthenticationHandler = interface(IMVCAuthenticationHandler)
|
||||
['{0B292EEF-B871-4FA9-81AC-FED633C3A238}']
|
||||
function SetOnRequest(AMethod: TMVCRequestDelegate): IMVCDefaultAuthenticationHandler;
|
||||
function SetOnAuthentication(AMethod: TMVCAuthenticationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
function SetOnAuthorization(AMethod: TMVCAuthorizationDelegate): IMVCDefaultAuthenticationHandler;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
_CanNotBeInstantiatedException = 'This class can not be instantiated!';
|
||||
|
||||
type
|
||||
|
||||
TMVCServerInfo = class(TInterfacedObject, IMVCServerInfo)
|
||||
strict private
|
||||
FServerName: string;
|
||||
FPort: Integer;
|
||||
FMaxConnections: Integer;
|
||||
FWebModuleClass: TComponentClass;
|
||||
FSecurity: IMVCSecurity;
|
||||
strict private
|
||||
function GetServerName(): string;
|
||||
procedure SetServerName(const AValue: string);
|
||||
|
||||
function GetPort(): Integer;
|
||||
procedure SetPort(const AValue: Integer);
|
||||
|
||||
function GetMaxConnections(): Integer;
|
||||
procedure SetMaxConnections(const AValue: Integer);
|
||||
|
||||
function GetWebModuleClass(): TComponentClass;
|
||||
procedure SetWebModuleClass(AValue: TComponentClass);
|
||||
|
||||
function GetSecurity(): IMVCSecurity;
|
||||
procedure SetSecurity(AValue: IMVCSecurity);
|
||||
|
||||
public
|
||||
constructor Create();
|
||||
destructor Destroy(); override;
|
||||
|
||||
property ServerName: string read GetServerName write SetServerName;
|
||||
property Port: Integer read GetPort write SetPort;
|
||||
property MaxConnections: Integer read GetMaxConnections write SetMaxConnections;
|
||||
property WebModuleClass: TComponentClass read GetWebModuleClass write SetWebModuleClass;
|
||||
property Security: IMVCSecurity read GetSecurity write SetSecurity;
|
||||
end;
|
||||
|
||||
TMVCServer = class(TInterfacedObject, IMVCServer)
|
||||
strict private
|
||||
|
||||
{$IFDEF IOCP}
|
||||
|
||||
FBridge: TIocpWebBrokerBridge;
|
||||
|
||||
{$ELSE}
|
||||
|
||||
FBridge: TIdHTTPWebBrokerBridge;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
FInfo: IMVCServerInfo;
|
||||
strict private
|
||||
function GetActive(): Boolean;
|
||||
function GetInfo(): IMVCServerInfo;
|
||||
procedure Configuration(AServerInfo: IMVCServerInfo);
|
||||
public
|
||||
constructor Create(AServerInfo: IMVCServerInfo);
|
||||
destructor Destroy(); override;
|
||||
|
||||
procedure Start();
|
||||
procedure Stop();
|
||||
|
||||
property Active: Boolean read GetActive;
|
||||
property Info: IMVCServerInfo read GetInfo;
|
||||
end;
|
||||
|
||||
TMVCServerContainer = class(TInterfacedObject, IMVCServerContainer)
|
||||
strict private
|
||||
FServers: TDictionary<string, IMVCServer>;
|
||||
strict private
|
||||
function GetServers(): TDictionary<string, IMVCServer>;
|
||||
public
|
||||
constructor Create();
|
||||
destructor Destroy(); override;
|
||||
|
||||
procedure CreateServer(AServerInfo: IMVCServerInfo);
|
||||
procedure DestroyServer(const AServerName: string);
|
||||
|
||||
procedure StartServers();
|
||||
procedure StopServers();
|
||||
|
||||
function FindServerByName(const AServerName: string): IMVCServer;
|
||||
|
||||
property Servers: TDictionary<string, IMVCServer> read GetServers;
|
||||
end;
|
||||
|
||||
TMVCSingletonServerContainer = class sealed
|
||||
strict private
|
||||
class var CriticalSection: TCriticalSection;
|
||||
class var ServerContainer: IMVCServerContainer;
|
||||
|
||||
class constructor Create;
|
||||
class destructor Destroy;
|
||||
public
|
||||
class function GetInstance(): IMVCServerContainer; static;
|
||||
end;
|
||||
|
||||
{ TMVCServerInfo }
|
||||
|
||||
constructor TMVCServerInfo.Create;
|
||||
begin
|
||||
FServerName := EmptyStr;
|
||||
FPort := 0;
|
||||
FMaxConnections := 0;
|
||||
FWebModuleClass := nil;
|
||||
FSecurity := nil;
|
||||
end;
|
||||
|
||||
destructor TMVCServerInfo.Destroy;
|
||||
begin
|
||||
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMVCServerInfo.GetMaxConnections: Integer;
|
||||
begin
|
||||
if (FMaxConnections = 0) then
|
||||
raise EMVCServerException.Create('MaxConnections was not informed!');
|
||||
Result := FMaxConnections;
|
||||
end;
|
||||
|
||||
function TMVCServerInfo.GetPort: Integer;
|
||||
begin
|
||||
if (FPort = 0) then
|
||||
raise EMVCServerException.Create('Port was not informed!');
|
||||
Result := FPort;
|
||||
end;
|
||||
|
||||
function TMVCServerInfo.GetSecurity: IMVCSecurity;
|
||||
begin
|
||||
Result := FSecurity;
|
||||
end;
|
||||
|
||||
function TMVCServerInfo.GetServerName: string;
|
||||
begin
|
||||
if (FServerName = EmptyStr) then
|
||||
raise EMVCServerException.Create('ServerName was not informed!');
|
||||
Result := FServerName;
|
||||
end;
|
||||
|
||||
function TMVCServerInfo.GetWebModuleClass: TComponentClass;
|
||||
begin
|
||||
if (FWebModuleClass = nil) then
|
||||
raise EMVCServerException.Create('WebModuleClass was not informed!');
|
||||
Result := FWebModuleClass;
|
||||
end;
|
||||
|
||||
procedure TMVCServerInfo.SetMaxConnections(const AValue: Integer);
|
||||
begin
|
||||
FMaxConnections := AValue;
|
||||
end;
|
||||
|
||||
procedure TMVCServerInfo.SetPort(const AValue: Integer);
|
||||
begin
|
||||
FPort := AValue;
|
||||
end;
|
||||
|
||||
procedure TMVCServerInfo.SetSecurity(AValue: IMVCSecurity);
|
||||
begin
|
||||
FSecurity := AValue;
|
||||
end;
|
||||
|
||||
procedure TMVCServerInfo.SetServerName(const AValue: string);
|
||||
begin
|
||||
FServerName := AValue;
|
||||
end;
|
||||
|
||||
procedure TMVCServerInfo.SetWebModuleClass(AValue: TComponentClass);
|
||||
begin
|
||||
FWebModuleClass := AValue;
|
||||
end;
|
||||
|
||||
{ TMVCServerInfoFactory }
|
||||
|
||||
class function TMVCServerInfoFactory.Build: IMVCServerInfo;
|
||||
begin
|
||||
Result := TMVCServerInfo.Create;
|
||||
end;
|
||||
|
||||
constructor TMVCServerInfoFactory.Create;
|
||||
begin
|
||||
raise EMVCServerException.Create(_CanNotBeInstantiatedException);
|
||||
end;
|
||||
|
||||
{ TMVCServer }
|
||||
|
||||
procedure TMVCServer.Configuration(AServerInfo: IMVCServerInfo);
|
||||
begin
|
||||
if (AServerInfo = nil) then
|
||||
raise EMVCServerException.Create('ServerInfo was not informed!');
|
||||
|
||||
FInfo := AServerInfo;
|
||||
|
||||
{$IFDEF IOCP}
|
||||
|
||||
FBridge := TIocpWebBrokerBridge.Create(nil);
|
||||
Stop();
|
||||
FBridge.Port := FInfo.Port;
|
||||
FBridge.MaxClients := FInfo.MaxConnections;
|
||||
FBridge.RegisterWebModuleClass(FInfo.WebModuleClass);
|
||||
|
||||
{$ELSE}
|
||||
|
||||
FBridge := TIdHTTPWebBrokerBridge.Create(nil);
|
||||
Stop();
|
||||
FBridge.DefaultPort := FInfo.Port;
|
||||
FBridge.MaxConnections := FInfo.MaxConnections;
|
||||
FBridge.RegisterWebModuleClass(FInfo.WebModuleClass);
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
end;
|
||||
|
||||
constructor TMVCServer.Create(AServerInfo: IMVCServerInfo);
|
||||
begin
|
||||
Configuration(AServerInfo);
|
||||
end;
|
||||
|
||||
destructor TMVCServer.Destroy;
|
||||
begin
|
||||
if (FBridge <> nil) then
|
||||
FreeAndNil(FBridge);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMVCServer.GetActive: Boolean;
|
||||
begin
|
||||
Result := FBridge.Active;
|
||||
end;
|
||||
|
||||
function TMVCServer.GetInfo: IMVCServerInfo;
|
||||
begin
|
||||
if (FInfo = nil) then
|
||||
raise EMVCServerException.Create('Server Info was not informed!');
|
||||
|
||||
Result := FInfo;
|
||||
end;
|
||||
|
||||
procedure TMVCServer.Start;
|
||||
begin
|
||||
FBridge.Active := True;
|
||||
end;
|
||||
|
||||
procedure TMVCServer.Stop;
|
||||
begin
|
||||
FBridge.Active := False;
|
||||
end;
|
||||
|
||||
{ TMVCServerFactory }
|
||||
|
||||
class function TMVCServerFactory.Build(AServerInfo: IMVCServerInfo): IMVCServer;
|
||||
begin
|
||||
Result := TMVCServer.Create(AServerInfo);
|
||||
end;
|
||||
|
||||
constructor TMVCServerFactory.Create;
|
||||
begin
|
||||
raise EMVCServerException.Create(_CanNotBeInstantiatedException);
|
||||
end;
|
||||
|
||||
{ TMVCServerContainer }
|
||||
|
||||
constructor TMVCServerContainer.Create;
|
||||
begin
|
||||
FServers := TDictionary<string, IMVCServer>.Create;
|
||||
end;
|
||||
|
||||
procedure TMVCServerContainer.CreateServer(AServerInfo: IMVCServerInfo);
|
||||
var
|
||||
vServer: IMVCServer;
|
||||
vPair: TPair<string, IMVCServer>;
|
||||
begin
|
||||
if not(FServers.ContainsKey(AServerInfo.ServerName)) then
|
||||
begin
|
||||
for vPair in FServers do
|
||||
if (vPair.Value.Info.WebModuleClass = AServerInfo.WebModuleClass) then
|
||||
raise EMVCServerException.Create('Server List already contains ' + AServerInfo.WebModuleClass.ClassName + '!');
|
||||
|
||||
vServer := TMVCServerFactory.Build(AServerInfo);
|
||||
FServers.Add(AServerInfo.ServerName, vServer);
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TMVCServerContainer.Destroy;
|
||||
begin
|
||||
StopServers();
|
||||
FreeAndNil(FServers);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TMVCServerContainer.DestroyServer(const AServerName: string);
|
||||
begin
|
||||
if (FServers.ContainsKey(AServerName)) then
|
||||
FServers.Remove(AServerName)
|
||||
else
|
||||
raise EMVCServerException.Create('Server ' + AServerName + ' not found!');
|
||||
end;
|
||||
|
||||
function TMVCServerContainer.FindServerByName(const AServerName: string): IMVCServer;
|
||||
begin
|
||||
try
|
||||
Result := FServers.Items[AServerName];
|
||||
except
|
||||
Result := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMVCServerContainer.GetServers: TDictionary<string, IMVCServer>;
|
||||
begin
|
||||
Result := FServers;
|
||||
end;
|
||||
|
||||
procedure TMVCServerContainer.StartServers;
|
||||
var
|
||||
vPair: TPair<string, IMVCServer>;
|
||||
begin
|
||||
for vPair in FServers do
|
||||
vPair.Value.Start();
|
||||
end;
|
||||
|
||||
procedure TMVCServerContainer.StopServers;
|
||||
var
|
||||
vPair: TPair<string, IMVCServer>;
|
||||
begin
|
||||
for vPair in FServers do
|
||||
vPair.Value.Stop();
|
||||
end;
|
||||
|
||||
{ TMVCServerContainerFactory }
|
||||
|
||||
class function TMVCServerContainerFactory.Build: IMVCServerContainer;
|
||||
begin
|
||||
Result := TMVCServerContainer.Create;
|
||||
end;
|
||||
|
||||
constructor TMVCServerContainerFactory.Create;
|
||||
begin
|
||||
raise EMVCServerException.Create(_CanNotBeInstantiatedException);
|
||||
end;
|
||||
|
||||
{ TMVCDefaultSecurity }
|
||||
|
||||
constructor TMVCDefaultSecurity.Create(AAuthenticationDelegate: TMVCAuthenticationDelegate;
|
||||
AAuthorizationDelegate: TMVCAuthorizationDelegate);
|
||||
begin
|
||||
FAuthenticationDelegate := AAuthenticationDelegate;
|
||||
FAuthorizationDelegate := AAuthorizationDelegate;
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultSecurity.OnAuthentication(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var AIsValid: Boolean; const ASessionData: TDictionary<String, String>);
|
||||
begin
|
||||
AIsValid := True;
|
||||
if Assigned(FAuthenticationDelegate) then
|
||||
FAuthenticationDelegate(AUserName, APassword, AUserRoles, AIsValid, ASessionData);
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultSecurity.OnAuthorization(AUserRoles: TList<string>;
|
||||
const AControllerQualifiedClassName, AActionName: string; var AIsAuthorized: Boolean);
|
||||
begin
|
||||
AIsAuthorized := True;
|
||||
if Assigned(FAuthorizationDelegate) then
|
||||
FAuthorizationDelegate(AUserRoles, AControllerQualifiedClassName, AActionName, AIsAuthorized);
|
||||
end;
|
||||
|
||||
procedure TMVCDefaultSecurity.OnRequest(const AControllerQualifiedClassName, AActionName: string;
|
||||
var AAuthenticationRequired: Boolean);
|
||||
begin
|
||||
AAuthenticationRequired := True;
|
||||
end;
|
||||
|
||||
{ TMVCSingletonServerContainer }
|
||||
|
||||
class constructor TMVCSingletonServerContainer.Create;
|
||||
begin
|
||||
CriticalSection := TCriticalSection.Create();
|
||||
ServerContainer := nil;
|
||||
end;
|
||||
|
||||
class destructor TMVCSingletonServerContainer.Destroy;
|
||||
begin
|
||||
ServerContainer := nil;
|
||||
FreeAndNil(CriticalSection);
|
||||
end;
|
||||
|
||||
class function TMVCSingletonServerContainer.GetInstance: IMVCServerContainer;
|
||||
begin
|
||||
if (ServerContainer = nil) then
|
||||
begin
|
||||
CriticalSection.Enter;
|
||||
try
|
||||
ServerContainer := TMVCServerContainerFactory.Build();
|
||||
finally
|
||||
CriticalSection.Leave;
|
||||
end;
|
||||
end;
|
||||
Result := ServerContainer;
|
||||
end;
|
||||
|
||||
{ MVCServerDefault }
|
||||
|
||||
class function MVCServerDefault.Container: IMVCServerContainer;
|
||||
begin
|
||||
Result := TMVCSingletonServerContainer.GetInstance;
|
||||
end;
|
||||
|
||||
constructor MVCServerDefault.Create;
|
||||
begin
|
||||
raise EMVCServerException.Create(_CanNotBeInstantiatedException);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -53,35 +53,35 @@ implementation
|
||||
|
||||
procedure TAppController.GetUser(ctx: TWebContext);
|
||||
var
|
||||
vUser: TAppUser;
|
||||
LUser: TAppUser;
|
||||
begin
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := 1;
|
||||
vUser.Name := 'Ezequiel';
|
||||
vUser.Pass := '123';
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := 1;
|
||||
LUser.Name := 'Ezequiel';
|
||||
LUser.Pass := '123';
|
||||
|
||||
Render(vUser);
|
||||
Render(LUser);
|
||||
end;
|
||||
|
||||
procedure TAppController.GetUsers(ctx: TWebContext);
|
||||
var
|
||||
vUsers: TObjectList<TAppUser>;
|
||||
vUser: TAppUser;
|
||||
LUsers: TObjectList<TAppUser>;
|
||||
LUser: TAppUser;
|
||||
I: Integer;
|
||||
begin
|
||||
vUsers := TObjectList<TAppUser>.Create(True);
|
||||
LUsers := TObjectList<TAppUser>.Create(True);
|
||||
|
||||
for I := 0 to 10 do
|
||||
begin
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := I;
|
||||
vUser.Name := 'Ezequiel ' + IntToStr(I);
|
||||
vUser.Pass := IntToStr(I);
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := I;
|
||||
LUser.Name := 'Ezequiel ' + IntToStr(I);
|
||||
LUser.Pass := IntToStr(I);
|
||||
|
||||
vUsers.Add(vUser);
|
||||
LUsers.Add(LUser);
|
||||
end;
|
||||
|
||||
Self.Render<TAppUser>(vUsers);
|
||||
Self.Render<TAppUser>(LUsers);
|
||||
end;
|
||||
|
||||
procedure TAppController.HelloWorld(ctx: TWebContext);
|
||||
@ -91,31 +91,31 @@ end;
|
||||
|
||||
procedure TAppController.PostUser(ctx: TWebContext);
|
||||
var
|
||||
vUser: TAppUser;
|
||||
LUser: TAppUser;
|
||||
begin
|
||||
vUser := ctx.Request.BodyAs<TAppUser>();
|
||||
LUser := ctx.Request.BodyAs<TAppUser>();
|
||||
|
||||
if (vUser.Cod > 0) then
|
||||
if (LUser.Cod > 0) then
|
||||
Render('Sucess!')
|
||||
else
|
||||
Render('Error!');
|
||||
|
||||
FreeAndNil(vUser);
|
||||
LUser.Free;
|
||||
end;
|
||||
|
||||
procedure TAppController.PostUsers(ctx: TWebContext);
|
||||
var
|
||||
vUsers: TObjectList<TAppUser>;
|
||||
LUsers: TObjectList<TAppUser>;
|
||||
begin
|
||||
vUsers := ctx.Request.BodyAsListOf<TAppUser>();
|
||||
vUsers.OwnsObjects := True;
|
||||
LUsers := ctx.Request.BodyAsListOf<TAppUser>();
|
||||
LUsers.OwnsObjects := True;
|
||||
|
||||
if (vUsers.Count > 0) then
|
||||
if (LUsers.Count > 0) then
|
||||
Render('Sucess!')
|
||||
else
|
||||
Render('Error!');
|
||||
|
||||
FreeAndNil(vUsers);
|
||||
LUsers.Free;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -10,6 +10,7 @@ uses
|
||||
ObjectsMappers,
|
||||
MVCFramework,
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl,
|
||||
MVCFramework.RESTClient,
|
||||
MVCFramework.RESTAdapter,
|
||||
MVCFramework.Commons,
|
||||
@ -40,6 +41,7 @@ type
|
||||
|
||||
TTestRESTClient = class(TTestCase)
|
||||
strict private
|
||||
FServerListener: IMVCListener;
|
||||
FRESTClient: TRESTClient;
|
||||
FRESTAdapter: TRESTAdapter<IAppResource>;
|
||||
FAppResource: IAppResource;
|
||||
@ -65,89 +67,79 @@ uses
|
||||
{ TTestRESTClient }
|
||||
|
||||
procedure TTestRESTClient.SetUp;
|
||||
var
|
||||
vServerInfo: IMVCServerInfo;
|
||||
vOnAuthentication: TMVCAuthenticationDelegate;
|
||||
begin
|
||||
inherited;
|
||||
vServerInfo := TMVCServerInfoFactory.Build;
|
||||
vServerInfo.ServerName := 'ServerApp';
|
||||
vServerInfo.Port := 3000;
|
||||
vServerInfo.MaxConnections := 1024;
|
||||
vServerInfo.WebModuleClass := TestWebModuleClass;
|
||||
|
||||
vOnAuthentication := procedure(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var AIsValid: Boolean; const ASessionData: TDictionary<String, String>)
|
||||
begin
|
||||
AIsValid := AUserName.Equals('ezequiel') and APassword.Equals('123');
|
||||
end;
|
||||
|
||||
vServerInfo.Security := TMVCDefaultSecurity.Create(vOnAuthentication, nil);
|
||||
|
||||
MVCServerDefault.Container.CreateServer(vServerInfo);
|
||||
MVCServerDefault.Container.StartServers;
|
||||
FServerListener := TMVCListener.Create(TMVCListenerProperties.New
|
||||
.SetName('AppServer')
|
||||
.SetPort(3000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(TestWebModuleClass)
|
||||
);
|
||||
FServerListener.Start;
|
||||
|
||||
FRESTClient := TRESTClient.Create('localhost', 3000);
|
||||
|
||||
FRESTAdapter := TRESTAdapter<IAppResource>.Create;
|
||||
FRESTAdapter.Build(FRESTClient);
|
||||
|
||||
FAppResource := FRESTAdapter.ResourcesService;
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TearDown;
|
||||
begin
|
||||
inherited;
|
||||
MVCServerDefault.Container.StopServers;
|
||||
FreeAndNil(FRESTClient);
|
||||
FServerListener.Stop;
|
||||
FRESTClient.Free;
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestCreateAndDestroy;
|
||||
var
|
||||
vClient: TRESTClient;
|
||||
LClient: TRESTClient;
|
||||
begin
|
||||
vClient := TRESTClient.Create('', 80, nil);
|
||||
CheckTrue(vClient <> nil);
|
||||
FreeAndNil(vClient);
|
||||
CheckTrue(vClient = nil);
|
||||
LClient := TRESTClient.Create('', 80, nil);
|
||||
CheckTrue(LClient <> nil);
|
||||
FreeAndNil(LClient);
|
||||
CheckTrue(LClient = nil);
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestGetUser;
|
||||
var
|
||||
vUser: TAppUser;
|
||||
vResp: IRESTResponse;
|
||||
LUser: TAppUser;
|
||||
LResp: IRESTResponse;
|
||||
begin
|
||||
FRESTClient.Resource('/user').Params([]);
|
||||
FRESTClient.Authentication('ezequiel', '123');
|
||||
FRESTClient.Authentication('dmvc', '123');
|
||||
|
||||
// String
|
||||
vResp := FRESTClient.doGET;
|
||||
LResp := FRESTClient.doGET;
|
||||
CheckTrue(
|
||||
('{"Cod":1,"Name":"Ezequiel","Pass":"123"}' = vResp.BodyAsString) and
|
||||
(vResp.ResponseCode = 200)
|
||||
('{"Cod":1,"Name":"Ezequiel","Pass":"123"}' = LResp.BodyAsString) and
|
||||
(LResp.ResponseCode = 200)
|
||||
);
|
||||
|
||||
// Object
|
||||
vUser := FRESTClient.doGET.BodyAsJSONObject.AsObject<TAppUser>();
|
||||
LUser := FRESTClient.doGET.BodyAsJSONObject.AsObject<TAppUser>();
|
||||
try
|
||||
CheckTrue((vUser <> nil) and (vUser.Cod > 0));
|
||||
CheckTrue((LUser <> nil) and (LUser.Cod > 0));
|
||||
finally
|
||||
FreeAndNil(vUser);
|
||||
FreeAndNil(LUser);
|
||||
end;
|
||||
|
||||
// Adapter
|
||||
vUser := FAppResource.GetUser;
|
||||
LUser := FAppResource.GetUser;
|
||||
try
|
||||
CheckTrue((vUser <> nil) and (vUser.Cod > 0));
|
||||
CheckTrue((LUser <> nil) and (LUser.Cod > 0));
|
||||
finally
|
||||
FreeAndNil(vUser);
|
||||
FreeAndNil(LUser);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestGetUsers;
|
||||
var
|
||||
vUsers: TObjectList<TAppUser>;
|
||||
LUsers: TObjectList<TAppUser>;
|
||||
begin
|
||||
FRESTClient.Resource('/users').Params([]);
|
||||
FRESTClient.Authentication('ezequiel', '123');
|
||||
FRESTClient.Authentication('dmvc', '123');
|
||||
|
||||
// String
|
||||
CheckEqualsString('[{"Cod":0,"Name":"Ezequiel 0","Pass":"0"},{"Cod":1,"Name":"Ezequiel 1","Pass":"1"},' +
|
||||
@ -157,28 +149,28 @@ begin
|
||||
FRESTClient.doGET.BodyAsString);
|
||||
|
||||
// Objects
|
||||
vUsers := FRESTClient.doGET.BodyAsJSONArray.AsObjectList<TAppUser>;
|
||||
LUsers := FRESTClient.doGET.BodyAsJSONArray.AsObjectList<TAppUser>;
|
||||
try
|
||||
vUsers.OwnsObjects := True;
|
||||
CheckTrue(vUsers.Count > 0);
|
||||
LUsers.OwnsObjects := True;
|
||||
CheckTrue(LUsers.Count > 0);
|
||||
finally
|
||||
FreeAndNil(vUsers);
|
||||
FreeAndNil(LUsers);
|
||||
end;
|
||||
|
||||
// Adapter
|
||||
vUsers := FAppResource.GetUsers;
|
||||
LUsers := FAppResource.GetUsers;
|
||||
try
|
||||
vUsers.OwnsObjects := True;
|
||||
CheckTrue(vUsers.Count > 0);
|
||||
LUsers.OwnsObjects := True;
|
||||
CheckTrue(LUsers.Count > 0);
|
||||
finally
|
||||
FreeAndNil(vUsers);
|
||||
FreeAndNil(LUsers);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestHelloWorld;
|
||||
begin
|
||||
FRESTClient.Resource('/hello').Params([]);
|
||||
FRESTClient.Authentication('ezequiel', '123');
|
||||
FRESTClient.Authentication('dmvc', '123');
|
||||
|
||||
// String
|
||||
CheckEqualsString('"Hello World called with GET"', FRESTClient.doGET.BodyAsString);
|
||||
@ -189,10 +181,10 @@ end;
|
||||
|
||||
procedure TTestRESTClient.TestInformation;
|
||||
var
|
||||
vClient: TRESTClient;
|
||||
LClient: TRESTClient;
|
||||
begin
|
||||
vClient := TRESTClient.Create('', 80, nil);
|
||||
vClient
|
||||
LClient := TRESTClient.Create('', 80, nil);
|
||||
LClient
|
||||
.ReadTimeOut(100)
|
||||
.ConnectionTimeOut(100)
|
||||
.Authentication('dmvc', 'dmvc', True)
|
||||
@ -204,84 +196,84 @@ begin
|
||||
.SSL
|
||||
.Compression;
|
||||
|
||||
CheckTrue(vClient.ReadTimeOut = 100);
|
||||
CheckTrue(vClient.ConnectionTimeOut = 100);
|
||||
CheckTrue(vClient.Username = 'dmvc');
|
||||
CheckTrue(vClient.Password = 'dmvc');
|
||||
CheckTrue(vClient.UseBasicAuthentication);
|
||||
CheckTrue(vClient.Accept = 'application/json;charset=UTF-8');
|
||||
CheckTrue(vClient.ContentType = 'application/json;charset=UTF-8');
|
||||
CheckTrue(vClient.ContentEncoding = 'UTF-8');
|
||||
CheckTrue(vClient.HasSSL);
|
||||
CheckTrue(vClient.HasCompression);
|
||||
CheckTrue(LClient.ReadTimeOut = 100);
|
||||
CheckTrue(LClient.ConnectionTimeOut = 100);
|
||||
CheckTrue(LClient.Username = 'dmvc');
|
||||
CheckTrue(LClient.Password = 'dmvc');
|
||||
CheckTrue(LClient.UseBasicAuthentication);
|
||||
CheckTrue(LClient.Accept = 'application/json;charset=UTF-8');
|
||||
CheckTrue(LClient.ContentType = 'application/json;charset=UTF-8');
|
||||
CheckTrue(LClient.ContentEncoding = 'UTF-8');
|
||||
CheckTrue(LClient.HasSSL);
|
||||
CheckTrue(LClient.HasCompression);
|
||||
|
||||
CheckTrue(vClient.RawBody <> nil);
|
||||
CheckTrue(vClient.MultiPartFormData <> nil);
|
||||
CheckTrue(vClient.BodyParams <> nil);
|
||||
CheckTrue(vClient.RequestHeaders <> nil);
|
||||
CheckTrue(vClient.QueryStringParams <> nil);
|
||||
CheckTrue(LClient.RawBody <> nil);
|
||||
CheckTrue(LClient.MultiPartFormData <> nil);
|
||||
CheckTrue(LClient.BodyParams <> nil);
|
||||
CheckTrue(LClient.RequestHeaders <> nil);
|
||||
CheckTrue(LClient.QueryStringParams <> nil);
|
||||
|
||||
FreeAndNil(vClient);
|
||||
FreeAndNil(LClient);
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestPostUser;
|
||||
var
|
||||
vUser: TAppUser;
|
||||
vResp: IRESTResponse;
|
||||
LUser: TAppUser;
|
||||
LResp: IRESTResponse;
|
||||
begin
|
||||
FRESTClient.Resource('/user/save').Params([]);
|
||||
FRESTClient.Authentication('ezequiel', '123');
|
||||
FRESTClient.Authentication('dmvc', '123');
|
||||
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := 1;
|
||||
vUser.Name := 'Ezequiel';
|
||||
vUser.Pass := '123';
|
||||
vResp := FRESTClient.doPOST<TAppUser>(vUser);
|
||||
CheckTrue(('"Sucess!"' = vResp.BodyAsString) and (vResp.ResponseCode = 200));
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := 1;
|
||||
LUser.Name := 'Ezequiel';
|
||||
LUser.Pass := '123';
|
||||
LResp := FRESTClient.doPOST<TAppUser>(LUser);
|
||||
CheckTrue(('"Sucess!"' = LResp.BodyAsString) and (LResp.ResponseCode = 200));
|
||||
|
||||
// Adapter
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := 1;
|
||||
vUser.Name := 'Ezequiel';
|
||||
vUser.Pass := '123';
|
||||
FAppResource.PostUser(vUser);
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := 1;
|
||||
LUser.Name := 'Ezequiel';
|
||||
LUser.Pass := '123';
|
||||
FAppResource.PostUser(LUser);
|
||||
end;
|
||||
|
||||
procedure TTestRESTClient.TestPostUsers;
|
||||
var
|
||||
vUsers: TObjectList<TAppUser>;
|
||||
vResp: IRESTResponse;
|
||||
LUsers: TObjectList<TAppUser>;
|
||||
LResp: IRESTResponse;
|
||||
I: Integer;
|
||||
vUser: TAppUser;
|
||||
LUser: TAppUser;
|
||||
begin
|
||||
FRESTClient.Resource('/users/save').Params([]);
|
||||
FRESTClient.Authentication('ezequiel', '123');
|
||||
FRESTClient.Authentication('dmvc', '123');
|
||||
FRESTClient.Accept('application/json;charset=utf-8');
|
||||
FRESTClient.ContentType('application/json;charset=utf-8');
|
||||
|
||||
vUsers := TObjectList<TAppUser>.Create(True);
|
||||
LUsers := TObjectList<TAppUser>.Create(True);
|
||||
for I := 0 to 10 do
|
||||
begin
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := I;
|
||||
vUser.Name := 'Ezequiel öüáàçãõºs ' + IntToStr(I);
|
||||
vUser.Pass := IntToStr(I);
|
||||
vUsers.Add(vUser);
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := I;
|
||||
LUser.Name := 'Ezequiel öüáàçãõºs ' + IntToStr(I);
|
||||
LUser.Pass := IntToStr(I);
|
||||
LUsers.Add(LUser);
|
||||
end;
|
||||
vResp := FRESTClient.doPOST<TAppUser>(vUsers);
|
||||
CheckTrue(('"Sucess!"' = vResp.BodyAsString) and (vResp.ResponseCode = 200));
|
||||
LResp := FRESTClient.doPOST<TAppUser>(LUsers);
|
||||
CheckTrue(('"Sucess!"' = LResp.BodyAsString) and (LResp.ResponseCode = 200));
|
||||
|
||||
// Adapter
|
||||
vUsers := TObjectList<TAppUser>.Create(True);
|
||||
LUsers := TObjectList<TAppUser>.Create(True);
|
||||
for I := 0 to 10 do
|
||||
begin
|
||||
vUser := TAppUser.Create;
|
||||
vUser.Cod := I;
|
||||
vUser.Name := 'Ezequiel öüáàçãõºs ' + IntToStr(I);
|
||||
vUser.Pass := IntToStr(I);
|
||||
vUsers.Add(vUser);
|
||||
LUser := TAppUser.Create;
|
||||
LUser.Cod := I;
|
||||
LUser.Name := 'Ezequiel öüáàçãõºs ' + IntToStr(I);
|
||||
LUser.Pass := IntToStr(I);
|
||||
LUsers.Add(LUser);
|
||||
end;
|
||||
FAppResource.PostUsers(vUsers);
|
||||
FAppResource.PostUsers(LUsers);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
@ -6,7 +6,8 @@ uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
Web.HTTPApp,
|
||||
MVCFramework;
|
||||
MVCFramework,
|
||||
System.Generics.Collections;
|
||||
|
||||
type
|
||||
|
||||
@ -28,28 +29,33 @@ uses
|
||||
MVCFramework.Tests.RESTClient,
|
||||
MVCFramework.Middleware.Authentication,
|
||||
MVCFramework.Tests.AppController,
|
||||
MVCFramework.Server;
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl;
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
procedure TTestWebModule.WebModuleCreate(Sender: TObject);
|
||||
var
|
||||
vServer: IMVCServer;
|
||||
begin
|
||||
FMVCEngine := TMVCEngine.Create(Self);
|
||||
|
||||
// Add Controller
|
||||
FMVCEngine.AddController(TAppController);
|
||||
|
||||
// Add Security Middleware
|
||||
vServer := MVCServerDefault.Container.FindServerByName('ServerApp');
|
||||
if (vServer <> nil) and (vServer.Info.Security <> nil) then
|
||||
FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(vServer.Info.Security));
|
||||
FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(
|
||||
TMVCDefaultAuthenticationHandler.New
|
||||
.SetOnAuthentication(
|
||||
procedure(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var IsValid: Boolean; const ASessionData: TDictionary<String, String>)
|
||||
begin
|
||||
IsValid := AUserName.Equals('dmvc') and APassword.Equals('123');
|
||||
end
|
||||
)
|
||||
));
|
||||
end;
|
||||
|
||||
procedure TTestWebModule.WebModuleDestroy(Sender: TObject);
|
||||
begin
|
||||
FreeAndNil(FMVCEngine);
|
||||
FMVCEngine.Free;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -6,14 +6,15 @@ uses
|
||||
TestFramework,
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
MVCFramework.Server,
|
||||
System.Generics.Collections,
|
||||
MVCFramework;
|
||||
MVCFramework,
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl;
|
||||
|
||||
type
|
||||
|
||||
[MVCPath('/')]
|
||||
TTestAppController = class(TMVCController)
|
||||
TTestController = class(TMVCController)
|
||||
public
|
||||
[MVCPath('/hello')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
@ -21,20 +22,17 @@ type
|
||||
end;
|
||||
|
||||
TTestMVCFrameworkServer = class(TTestCase)
|
||||
strict private
|
||||
private
|
||||
|
||||
protected
|
||||
procedure SetUp; override;
|
||||
procedure TearDown; override;
|
||||
published
|
||||
procedure TestCreateServer();
|
||||
procedure TestServerContainer();
|
||||
procedure TestServerAndClient();
|
||||
procedure TestListener;
|
||||
procedure TestListenerContext;
|
||||
procedure TestServerListenerAndClient;
|
||||
end;
|
||||
|
||||
var
|
||||
ServerContainer: IMVCServerContainer;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -55,90 +53,100 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TTestMVCFrameworkServer.TestCreateServer;
|
||||
procedure TTestMVCFrameworkServer.TestListener;
|
||||
var
|
||||
vServerInfo: IMVCServerInfo;
|
||||
vServer: IMVCServer;
|
||||
LListener: IMVCListener;
|
||||
begin
|
||||
vServerInfo := TMVCServerInfoFactory.Build;
|
||||
vServerInfo.ServerName := 'ServerTemp';
|
||||
vServerInfo.Port := 4000;
|
||||
vServerInfo.MaxConnections := 1024;
|
||||
vServerInfo.WebModuleClass := TestWebModuleClass;
|
||||
LListener := TMVCListener.Create(TMVCListenerProperties.New
|
||||
.SetName('Listener1')
|
||||
.SetPort(5000)
|
||||
.SetMaxConnections(512)
|
||||
.SetWebModuleClass(TestWebModuleClass)
|
||||
);
|
||||
|
||||
vServer := TMVCServerFactory.Build(vServerInfo);
|
||||
CheckTrue(Assigned(LListener));
|
||||
|
||||
CheckTrue(vServer.Info <> nil);
|
||||
LListener.Start;
|
||||
CheckTrue(LListener.Active);
|
||||
|
||||
vServer.Start;
|
||||
CheckTrue(vServer.Active);
|
||||
|
||||
vServer.Stop;
|
||||
CheckFalse(vServer.Active);
|
||||
LListener.Stop;
|
||||
CheckFalse(LListener.Active);
|
||||
end;
|
||||
|
||||
procedure TTestMVCFrameworkServer.TestServerAndClient;
|
||||
procedure TTestMVCFrameworkServer.TestServerListenerAndClient;
|
||||
var
|
||||
vServerInfo: IMVCServerInfo;
|
||||
vOnAuthentication: TMVCAuthenticationDelegate;
|
||||
vRESTCli: TRESTClient;
|
||||
LListener: IMVCListener;
|
||||
LClient: TRESTClient;
|
||||
begin
|
||||
vServerInfo := TMVCServerInfoFactory.Build;
|
||||
vServerInfo.ServerName := 'ServerTemp';
|
||||
vServerInfo.Port := 6000;
|
||||
vServerInfo.MaxConnections := 1024;
|
||||
vServerInfo.WebModuleClass := TestWebModuleClass;
|
||||
LListener := TMVCListener.Create(TMVCListenerProperties.New
|
||||
.SetName('Listener1')
|
||||
.SetPort(6000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(TestWebModuleClass)
|
||||
);
|
||||
|
||||
vOnAuthentication := procedure(const pUserName, pPassword: string;
|
||||
pUserRoles: TList<string>; var pIsValid: Boolean; const pSessionData: TDictionary<String, String>)
|
||||
begin
|
||||
pIsValid := pUserName.Equals('ezequiel') and pPassword.Equals('123');
|
||||
end;
|
||||
CheckTrue(Assigned(LListener));
|
||||
|
||||
vServerInfo.Security := TMVCDefaultSecurity.Create(vOnAuthentication, nil);
|
||||
LListener.Start;
|
||||
CheckTrue(LListener.Active);
|
||||
|
||||
if (ServerContainer.FindServerByName('ServerTemp') <> nil) then
|
||||
ServerContainer.DestroyServer('ServerTemp');
|
||||
|
||||
ServerContainer.CreateServer(vServerInfo);
|
||||
ServerContainer.StartServers;
|
||||
|
||||
vRESTCli := TRESTClient.Create('localhost', 6000);
|
||||
LClient := TRESTClient.Create('localhost', 6000);
|
||||
try
|
||||
vRESTCli.UserName := 'ezequiel';
|
||||
vRESTCli.Password := '123';
|
||||
CheckEqualsString('"Hello World called with GET"', vRESTCli.doGET('/hello', []).BodyAsString);
|
||||
LClient.UserName := 'dmvc';
|
||||
LClient.Password := '123';
|
||||
CheckEqualsString('"Hello World called with GET"', LClient.doGET('/hello', []).BodyAsString);
|
||||
finally
|
||||
FreeAndNil(vRESTCli);
|
||||
FreeAndNil(LClient);
|
||||
end;
|
||||
|
||||
ServerContainer.StopServers;
|
||||
LListener.Stop;
|
||||
CheckFalse(LListener.Active);
|
||||
end;
|
||||
|
||||
procedure TTestMVCFrameworkServer.TestServerContainer;
|
||||
procedure TTestMVCFrameworkServer.TestListenerContext;
|
||||
var
|
||||
vServerInfo: IMVCServerInfo;
|
||||
vContainer: IMVCServerContainer;
|
||||
LListenerCtx: IMVCListenersContext;
|
||||
begin
|
||||
vServerInfo := TMVCServerInfoFactory.Build;
|
||||
vServerInfo.ServerName := 'ServerTemp';
|
||||
vServerInfo.Port := 4000;
|
||||
vServerInfo.MaxConnections := 1024;
|
||||
vServerInfo.WebModuleClass := TestWebModuleClass;
|
||||
LListenerCtx := TMVCListenersContext.Create;
|
||||
|
||||
vContainer := TMVCServerContainerFactory.Build();
|
||||
vContainer.CreateServer(vServerInfo);
|
||||
LListenerCtx.Add(TMVCListenerProperties.New
|
||||
.SetName('Listener2')
|
||||
.SetPort(6000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(TestWebModuleClass)
|
||||
);
|
||||
|
||||
CheckTrue(vContainer.FindServerByName('ServerTemp') <> nil);
|
||||
LListenerCtx.Add(TMVCListenerProperties.New
|
||||
.SetName('Listener3')
|
||||
.SetPort(7000)
|
||||
.SetMaxConnections(1024)
|
||||
.SetWebModuleClass(TestWebModuleClass2)
|
||||
);
|
||||
|
||||
vContainer.DestroyServer('ServerTemp');
|
||||
CheckTrue(Assigned(LListenerCtx.FindByName('Listener2')));
|
||||
CheckTrue(Assigned(LListenerCtx.FindByName('Listener3')));
|
||||
|
||||
CheckTrue(vContainer.FindServerByName('ServerTemp') = nil);
|
||||
LListenerCtx.StartAll;
|
||||
|
||||
CheckTrue(LListenerCtx.Count = 2);
|
||||
CheckTrue(LListenerCtx.FindByName('Listener2').Active);
|
||||
CheckTrue(LListenerCtx.FindByName('Listener3').Active);
|
||||
|
||||
LListenerCtx.StopAll;
|
||||
|
||||
CheckFalse(LListenerCtx.FindByName('Listener2').Active);
|
||||
CheckFalse(LListenerCtx.FindByName('Listener3').Active);
|
||||
|
||||
LListenerCtx
|
||||
.Remove('Listener2')
|
||||
.Remove('Listener3');
|
||||
|
||||
CheckTrue(LListenerCtx.Count = 0);
|
||||
end;
|
||||
|
||||
{ TTestAppController }
|
||||
{ TTestController }
|
||||
|
||||
procedure TTestAppController.HelloWorld(ctx: TWebContext);
|
||||
procedure TTestController.HelloWorld(ctx: TWebContext);
|
||||
begin
|
||||
Render('Hello World called with GET');
|
||||
end;
|
||||
@ -147,6 +155,4 @@ initialization
|
||||
|
||||
RegisterTest(TTestMVCFrameworkServer.Suite);
|
||||
|
||||
ServerContainer := MVCServerDefault.Container;
|
||||
|
||||
end.
|
||||
|
@ -5,6 +5,7 @@ interface
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
Web.HTTPApp,
|
||||
MVCFramework;
|
||||
|
||||
@ -21,39 +22,45 @@ type
|
||||
|
||||
var
|
||||
TestWebModuleClass: TComponentClass = TTestWebModule;
|
||||
TestWebModuleClass2: TComponentClass = TTestWebModule;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.Tests.StandaloneServer,
|
||||
MVCFramework.Middleware.Authentication,
|
||||
MVCFramework.Server;
|
||||
MVCFramework.Server,
|
||||
MVCFramework.Server.Impl;
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
procedure TTestWebModule.WebModuleCreate(Sender: TObject);
|
||||
var
|
||||
vServer: IMVCServer;
|
||||
begin
|
||||
FMVCEngine := TMVCEngine.Create(Self);
|
||||
|
||||
// Add With Delegate Constructor Controller
|
||||
FMVCEngine.AddController(TTestAppController,
|
||||
FMVCEngine.AddController(TTestController,
|
||||
function: TMVCController
|
||||
begin
|
||||
Result := TTestAppController.Create;
|
||||
Result := TTestController.Create;
|
||||
end
|
||||
);
|
||||
|
||||
// Add Security Middleware
|
||||
vServer := ServerContainer.FindServerByName('ServerTemp');
|
||||
if (vServer <> nil) and (vServer.Info.Security <> nil) then
|
||||
FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(vServer.Info.Security));
|
||||
FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(
|
||||
TMVCDefaultAuthenticationHandler.New
|
||||
.SetOnAuthentication(
|
||||
procedure(const AUserName, APassword: string;
|
||||
AUserRoles: TList<string>; var IsValid: Boolean; const ASessionData: TDictionary<String, String>)
|
||||
begin
|
||||
IsValid := AUserName.Equals('dmvc') and APassword.Equals('123');
|
||||
end
|
||||
)
|
||||
));
|
||||
end;
|
||||
|
||||
procedure TTestWebModule.WebModuleDestroy(Sender: TObject);
|
||||
begin
|
||||
FreeAndNil(FMVCEngine);
|
||||
FMVCEngine.Free;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user