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:
Ezequiel Juliano Müller 2016-06-16 17:13:35 -03:00
parent 0d0d2d7aad
commit 04b83cc0f5
12 changed files with 687 additions and 869 deletions

118
README.md
View File

@ -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;
```

View File

@ -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);

View File

@ -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>

View File

@ -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.

View 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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.