Merge branch 'master' into feature_filters

# Conflicts:
#	README.md
#	sources/MVCFramework.Filters.CORS.pas
#	sources/MVCFramework.pas
#	unittests/general/TestServer/TestServer.dpr
#	unittests/general/TestServer/TestServer.dproj
This commit is contained in:
Daniele Teti 2023-08-15 21:53:25 +02:00
commit 3ce7c55367
87 changed files with 8709 additions and 6780 deletions

1
.gitignore vendored
View File

@ -144,3 +144,4 @@ samples/WineCellarSample/winecellarclient_mobile/Android/Debug/styles.xml
samples/WineCellarSample/winecellarclient_mobile/Android/Debug/styles-v21.xml
samples/WineCellarSample/winecellarclient_mobile/Android/Debug/WineCellarMobileClient.classes/classes.dex
samples/apachemodule/Apache24/logs/httpd.pid
samples/session_file_based/Win32/DEBUG/sessions/

402
README.md
View File

@ -18,7 +18,7 @@
- [What users say about DMVCFramework](#what-users-say-about-dmvcframework)
- [What's New in dmvcframework-3.3.0-fluorine (last stable version)](#whats-new-in-dmvcframework-330-fluorine-last-stable-version)
- [What's New in the next "repo version" a.k.a. 3.4.0-neon](#whats-new-in-the-next-repo-version-aka-340-neon)
- [Hystorical Versions](#hystorical-versions)
- [Old Versions](#old-versions)
- [What's New in dmvcframework-3.2.3-radium](#whats-new-in-dmvcframework-323-radium)
- [Bug Fix in 3.2.3-radium](#bug-fix-in-323-radium)
- [What's new in DelphiMVCFramework-3.2.2-nitrogen](#whats-new-in-delphimvcframework-322-nitrogen)
@ -214,6 +214,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
> "Thank you for the great framework! We are very happy with this!" -- Andreas
> "I managed to generate an API for my application thanks to this framework, it is truly useful and efficient!" -- J. Urbani
## What's New in dmvcframework-3.3.0-fluorine (last stable version)
@ -231,20 +233,400 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
## What's New in the next "repo version" a.k.a. 3.4.0-neon
- Added support for dotEnv multiline keys - added dotEnv show case
- Added MSHeap memory manager for Win32 and Win64 (https://github.com/RDP1974/DelphiMSHeap)
- ⚡ Added support for dotEnv multiline keys - added dotEnv show case
- ⚡ Added MSHeap memory manager for Win32 and Win64 (https://github.com/RDP1974/DelphiMSHeap)
- 🐞 FIX [Issue 664](https://github.com/danieleteti/delphimvcframework/issues/664) Thanks to [MPannier](https://github.com/MPannier)
- 🐞 FIX [Issue 667](https://github.com/danieleteti/delphimvcframework/issues/667)
- 🐞 FIX [Issue 680](https://github.com/danieleteti/delphimvcframework/issues/680)
- 🐞 FIX Wrong comparison in checks for ro/RW/PK fields in `TMVCActiveRecord`
- Wizard updated to be dotEnv aware
- Removed Controller Application Session (very seldom used but potentially breaking change)
- Removed Middlewares in favor of a simpler alternative named "Filters"
- Added Protocol Filters
- Added Controller Filters
- `TMVCRouterLogHandlerProc` changed prototype (breaking change)
- 🐞 FIX wrong default initialization for JWT (thanks to Flavio Basile)
- ⚡ Wizard updated to be dotEnv aware
- ⚡ Added "Load Style" methods to `TMVCActiveRecord` as suggested by https://github.com/danieleteti/delphimvcframework/issues/675
- ⚡ Better error message in case of serialization of `TArray<TObject>`
- ⚡ Improved CORS handling - [Issue 679](https://github.com/danieleteti/delphimvcframework/issues/679) (Thanks to [David Moorhouse](https://github.com/fastbike))
- ⚡ Improved serialization of `TObjectList<TDataSet>` (however `ObjectDict` is still the preferred way to serialize multiple datasets).
- ⚡ Added static method for easier cloning of FireDAC dataset into `TFDMemTable`.
- `class function CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable`
- Check sample "function_actions_showcase.dproj" for more info.
- ⚡ Functional Actions
- In addition to the classic `procedure` based actions, now it's possibile to use functions as actions. The `Result` variable is automatically rendered and, if it is an object, its memory is freed.
```pascal
type
[MVCNameCase(ncCamelCase)]
TPersonRec = record
FirstName, LastName: String;
Age: Integer;
class function Create: TPersonRec; static;
end;
[MVCNameCase(ncCamelCase)]
TPerson = class
private
fAge: Integer;
fFirstName, fLastName: String;
public
property FirstName: String read fFirstName write fFirstName;
property LastName: String read fLastName write fLastName;
property Age: Integer read fAge write fAge;
end;
[MVCPath('/api')]
TMyController = class(TMVCController)
public
{ actions returning a simple type }
[MVCPath('/sumsasinteger/($A)/($B)')]
function GetSum(const A, B: Integer): Integer;
[MVCPath('/sumsasfloat/($A)/($B)')]
function GetSumAsFloat(const A, B: Extended): Extended;
{ actions returning records }
[MVCPath('/records/single')]
function GetSingleRecord: TPersonRec;
[MVCPath('/records/multiple')]
function GetMultipleRecords: TArray<TPersonRec>;
{ actions returning objects }
[MVCPath('/objects/single')]
function GetSingleObject: TPerson;
[MVCPath('/objects/multiple')]
function GetMultipleObjects: TObjectList<TPerson>;
{ actions returning datasets }
[MVCPath('/datasets/single')]
function GetSingleDataSet: TDataSet;
[MVCPath('/datasets/multiple')]
function GetMultipleDataSet: TEnumerable<TDataSet>;
[MVCPath('/datasets/multiple2')]
function GetMultipleDataSet2: IMVCObjectDictionary;
{ customize response headers }
[MVCPath('/headers')]
function GetWithCustomHeaders: TObjectList<TPerson>;
end;
```
Check sample "function_actions_showcase.dproj" for more info.
- ⚡ Improved `TMVCResponse` type to better suits the new functional actions.
`TMVCResponse` can be used with "message based" responses and also with "data based" responses (with single object, with a list of objects or with a dictionary of objects).
**Message based responses**
```pascal
function TMyController.GetMVCResponse: TMVCResponse;
begin
Result := MVCResponse(HTTP_STATUS.OK, 'My Message');
end;
```
Produces
```json
{
"message":"My Message"
}
```
**Data based response with single object**
```pascal
function TMyController.GetMVCResponse2: TMVCResponse;
begin
Result := MVCResponse(HTTP_STATUS.OK, TPerson.Create('Daniele','Teti', 99));
end;
```
Produces
```json
{
"data": {
"firstName": "Daniele",
"lastName": "Teti",
"age": 99
}
}
```
**Data based response with list of objects**
```pascal
function TMyController.GetMVCResponse3: TMVCResponse;
begin
Result := MVCResponse(HTTP_STATUS.OK,
TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
);
end;
```
Produces
```json
{
"data": [
{
"firstName": "Daniele",
"lastName": "Teti",
"age": 99
},
{
"firstName": "Peter",
"lastName": "Parker",
"age": 25
},
{
"firstName": "Bruce",
"lastName": "Banner",
"age": 45
}
]
}
```
**Data dictionary based response with `IMVCObjectDictionary` **
```pascal
function TMyController.GetMVCResponseWithObjectDictionary: IMVCResponse;
begin
Result := MVCResponse(
HTTP_STATUS.OK,
ObjectDict()
.Add('employees', TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
)
.Add('customers', TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
)
);
end;
```
Produces
```json
{
"employees": [
{
"firstName": "Daniele",
"lastName": "Teti",
"age": 99
},
{
"firstName": "Peter",
"lastName": "Parker",
"age": 25
},
{
"firstName": "Bruce",
"lastName": "Banner",
"age": 45
}
],
"customers": [
{
"firstName": "Daniele",
"lastName": "Teti",
"age": 99
},
{
"firstName": "Peter",
"lastName": "Parker",
"age": 25
},
{
"firstName": "Bruce",
"lastName": "Banner",
"age": 45
}
]
}
```
- Removed `statuscode` and `reasonstring` from exception's JSON rendering.
- ⚡ New! NamedQueries support for TMVCActiveRecord.
- `MVCNamedSQLQuery` allows to define a "named query" which is, well, a SQL query with a name. Then such query can be used by the method `SelectByNamedQuery<T>`. MOreover in the attribute it is possible to define on which backend engine that query is usable. In this way you can define optimized query for each supported DMBS you need. Check the example below.
```delphi
type
[MVCTable('customers')]
[MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc',
TMVCActiveRecordBackEnd.FirebirdSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc',
TMVCActiveRecordBackEnd.PostgreSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')]
TCustomer = class(TCustomEntity)
private
// usual field declaration
end;
//** then in the code
Log('** Named SQL Query');
Log('QuerySQL: RatingLessThanPar');
var lCustomers := TMVCActiveRecord.SelectByNamedQuery<TCustomer>('RatingLessThanPar', [4], [ftInteger]);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
Log('QuerySQL: RatingEqualsToPar');
lCustomers := TMVCActiveRecord.SelectByNamedQuery<TCustomer>('RatingEqualsToPar', [3], [ftInteger]);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
```
The same approach is available for RQL query, which can be used also for Count and Delete operations but doesnt allows to specify the backend (because RQL has an actual compiler to adapt the generated SQL to each RDBMS)
```delphi
type
[MVCTable('customers')]
[MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc',
TMVCActiveRecordBackEnd.FirebirdSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc',
TMVCActiveRecordBackEnd.PostgreSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')]
[MVCNamedRQLQuery('RatingLessThanPar', 'lt(rating,%d);sort(+code,-city)')]
[MVCNamedRQLQuery('RatingEqualsToPar', 'eq(rating,%d);sort(+code,-city)')]
TCustomer = class(TCustomEntity)
private
// usual field declaration
end;
//** then in the code
Log('** Named RQL Query');
Log('QueryRQL: RatingLessThanPar');
lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('RatingLessThanPar', [4], 1000);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
Log('QueryRQL: RatingEqualsToPar');
lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('RatingEqualsToPar', [3], 1000);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
```
Now, having SQL and RQL named queries, it is possibile to have an entity which is not mapped on a specific table but loaded only by named queries.
```delphi
type
[MVCEntityActions([eaRetrieve])]
[MVCNamedSQLQuery('CustomersInTheSameCity',
'SELECT c.id, c.DESCRIPTION, c.city, c.code, c.rating, (SELECT count(*) - 1 FROM customers c2 WHERE c2.CITY = c.CITY) customers_in_the_same_city ' +
'FROM CUSTOMERS c WHERE city IS NOT NULL AND city <> '''' ORDER BY customers_in_the_same_city')]
TCustomerStats = class(TCustomEntity) {not mapped on an actual table or view}
private
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
fID: NullableInt64;
[MVCTableField('code')]
fCode: NullableString;
[MVCTableField('description')]
fCompanyName: NullableString;
[MVCTableField('city')]
fCity: string;
[MVCTableField('rating')]
fRating: NullableInt32;
[MVCTableField('customers_in_the_same_city')]
fCustomersInTheSameCity: Int32;
public
property ID: NullableInt64 read fID write fID;
property Code: NullableString read fCode write fCode;
property CompanyName: NullableString read fCompanyName write fCompanyName;
property City: string read fCity write fCity;
property Rating: NullableInt32 read fRating write fRating;
property CustomersInTheSameCity: Int32 read fCustomersInTheSameCity write fCustomersInTheSameCity;
end;
//** then in the code
procedure TMainForm.btnVirtualEntitiesClick(Sender: TObject);
begin
var lCustStats := TMVCActiveRecord.SelectByNamedQuery<TCustomerStats>('CustomersInTheSameCity', [], []);
try
for var lCustomer in lCustStats do
begin
Log(Format('%4d - %8.5s - %s - (%d other customers in the same city)', [
lCustomer.ID.ValueOrDefault,
lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault,
lCustomer.CustomersInTheSameCity
]));
end;
finally
lCustStats.Free;
end;
end;
```
## Hystorical Versions
## Old Versions
### What's New in dmvcframework-3.2.3-radium

View File

@ -104,12 +104,19 @@ var
lActionFiltersMethodsImpl: string;
lCRUDMethodsIntf: string;
lCRUDMethodsImpl: string;
lBOClassesIntf: string;
lBOClassesImpl: string;
begin
lControllerUnit := sControllerUnit;
lIndexMethodIntf := sIndexMethodIntf;
lIndexMethodImpl := Format(sIndexMethodImpl, [FControllerClassName]);
lCRUDMethodsIntf := sCRUDMethodsIntf;
lCRUDMethodsImpl := Format(sCRUDMethodsImpl, [FControllerClassName]);
lBOClassesIntf := sBOClassesIntf;
lBOClassesImpl := Format(sBOClassesImpl, ['TPerson']);
if not FCreateIndexMethod then
begin
@ -121,6 +128,8 @@ begin
begin
lCRUDMethodsIntf := '';
lCRUDMethodsImpl := '';
lBOClassesIntf := '';
lBOClassesImpl := '';
end;
lActionFiltersMethodsIntf := sActionFiltersIntf;
@ -138,7 +147,18 @@ begin
(BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName('',
lUnitIdent, lFormName, lFileName);
Result := TSourceFile.Create(sControllerUnit,
[lUnitIdent, FControllerClassName, lIndexMethodIntf, lIndexMethodImpl, lActionFiltersMethodsIntf, lActionFiltersMethodsImpl, lCRUDMethodsIntf, lCRUDMethodsImpl]);
[
lUnitIdent,
FControllerClassName,
lIndexMethodIntf,
lIndexMethodImpl,
lActionFiltersMethodsIntf,
lActionFiltersMethodsImpl,
lCRUDMethodsIntf,
lCRUDMethodsImpl,
lBOClassesIntf,
lBOClassesImpl
]);
end;
{ TNewJSONRPCUnitEx }
@ -155,7 +175,6 @@ function TNewJSONRPCUnitEx.NewImplSource(const ModuleIdent, FormIdent,
AncestorIdent: string): IOTAFile;
var
lUnitIdent: string;
// lFormName: string;
lFileName: string;
lDummy: String;
begin

View File

@ -130,14 +130,18 @@ resourcestring
// 3 - Sample Methods - Implementation
// 4 - Action Filters - Interface
// 5 - Action Filters - Implementation
// 8 - BO - Interface
// 9 - BO - Implementation
sControllerUnit = 'unit %0:s;' + sLineBreak +
sLineBreak +
'interface' + sLineBreak +
sLineBreak +
'uses' + sLineBreak +
' MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons;' + sLineBreak +
' MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, System.Generics.Collections;' + sLineBreak +
sLineBreak +
'type' + sLineBreak +
'%8:s' + sLineBreak +
' [MVCPath(''/api'')]' + sLineBreak +
' %1:s = class(TMVCController) ' + sLineBreak +
' public' + sLineBreak +
@ -154,6 +158,7 @@ resourcestring
'%5:s' + sLineBreak +
'%7:s' + sLineBreak +
sLineBreak +
'%9:s' + sLineBreak +
'end.' + sLineBreak;
sIndexMethodIntf =
@ -162,6 +167,7 @@ resourcestring
' procedure Index;' + sLineBreak + sLineBreak +
' [MVCPath(''/reversedstrings/($Value)'')]' + sLineBreak +
' [MVCHTTPMethod([httpGET])]' + sLineBreak +
' [MVCProduces(TMVCMediaType.TEXT_PLAIN)]' + sLineBreak +
' procedure GetReversedString(const Value: String);' + sLineBreak;
// 0 - Class Name
@ -179,45 +185,66 @@ resourcestring
sCRUDMethodsIntf =
sLineBreak +
' public' + sLineBreak +
' //Sample CRUD Actions for a "Customer" entity' + sLineBreak +
' [MVCPath(''/customers'')]' + sLineBreak +
' //Sample CRUD Actions for a "People" entity' + sLineBreak +
' [MVCPath(''/people'')]' + sLineBreak +
' [MVCHTTPMethod([httpGET])]' + sLineBreak +
' procedure GetCustomers;' + sLineBreak + sLineBreak +
' [MVCPath(''/customers/($id)'')]' + sLineBreak +
' function GetPeople: TObjectList<TPerson>;' + sLineBreak + sLineBreak +
' [MVCPath(''/people/($ID)'')]' + sLineBreak +
' [MVCHTTPMethod([httpGET])]' + sLineBreak +
' procedure GetCustomer(id: Integer);' + sLineBreak + sLineBreak +
' [MVCPath(''/customers'')]' + sLineBreak +
' function GetPerson(ID: Integer): TPerson;' + sLineBreak + sLineBreak +
' [MVCPath(''/people'')]' + sLineBreak +
' [MVCHTTPMethod([httpPOST])]' + sLineBreak +
' procedure CreateCustomer;' + sLineBreak + sLineBreak +
' [MVCPath(''/customers/($id)'')]' + sLineBreak +
' function CreatePerson([MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + sLineBreak +
' [MVCPath(''/people/($ID)'')]' + sLineBreak +
' [MVCHTTPMethod([httpPUT])]' + sLineBreak +
' procedure UpdateCustomer(id: Integer);' + sLineBreak + sLineBreak +
' [MVCPath(''/customers/($id)'')]' + sLineBreak +
' function UpdatePerson(ID: Integer; [MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + sLineBreak +
' [MVCPath(''/people/($ID)'')]' + sLineBreak +
' [MVCHTTPMethod([httpDELETE])]' + sLineBreak +
' procedure DeleteCustomer(id: Integer);' + sLineBreak + sLineBreak;
' function DeletePerson(ID: Integer): TMVCResponse;' + sLineBreak + sLineBreak;
sCRUDMethodsImpl =
'//Sample CRUD Actions for a "Customer" entity' + sLineBreak +
'procedure %0:s.GetCustomers;' + sLineBreak +
'//Sample CRUD Actions for a "People" entity' + sLineBreak +
'function %0:s.GetPeople: TObjectList<TPerson>;' + sLineBreak +
'var' + sLineBreak +
' lPeople: TObjectList<TPerson>;' + sLineBreak +
'begin' + sLineBreak +
' //todo: render a list of customers' + sLineBreak +
' lPeople := TObjectList<TPerson>.Create(True);' + sLineBreak +
' try' + sLineBreak +
' lPeople.Add(TPerson.Create(''Peter'',''Parker'', EncodeDate(1965, 10, 4)));' + sLineBreak +
' lPeople.Add(TPerson.Create(''Bruce'',''Banner'', EncodeDate(1945, 9, 6)));' + sLineBreak +
' lPeople.Add(TPerson.Create(''Reed'',''Richards'', EncodeDate(1955, 3, 7)));' + sLineBreak +
' Result := lPeople;' + sLineBreak +
' except' + sLineBreak +
' lPeople.Free;' + sLineBreak +
' raise;' + sLineBreak +
' end;' + sLineBreak +
'end;' + sLineBreak + sLineBreak +
'procedure %0:s.GetCustomer(id: Integer);' + sLineBreak +
'function %0:s.GetPerson(ID: Integer): TPerson;' + sLineBreak +
'var' + sLineBreak +
' lPeople: TObjectList<TPerson>;' + sLineBreak +
'begin' + sLineBreak +
' //todo: render the customer by id' + sLineBreak +
' lPeople := GetPeople;' + sLineBreak +
' try' + sLineBreak +
' Result := lPeople.ExtractAt(ID mod lPeople.Count);' + sLineBreak +
' finally' + sLineBreak +
' lPeople.Free;' + sLineBreak +
' end;' + sLineBreak +
'end;' + sLineBreak + sLineBreak +
'procedure %0:s.CreateCustomer;' + sLineBreak +
'function %0:s.CreatePerson([MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak +
'begin' + sLineBreak +
' //todo: create a new customer' + sLineBreak +
' LogI(''Created '' + Person.FirstName + '' '' + Person.LastName);' + sLineBreak +
' Result := TMVCResponse.Create(HTTP_STATUS.Created, ''Person created'');' + sLineBreak +
'end;' + sLineBreak + sLineBreak +
'procedure %0:s.UpdateCustomer(id: Integer);' + sLineBreak +
'function %0:s.UpdatePerson(ID: Integer; [MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak +
'begin' + sLineBreak +
' //todo: update customer by id' + sLineBreak +
' LogI(''Updated '' + Person.FirstName + '' '' + Person.LastName);' + sLineBreak +
' Result := TMVCResponse.Create(HTTP_STATUS.OK, ''Person updated'');' + sLineBreak +
'end;' + sLineBreak + sLineBreak +
'procedure %0:s.DeleteCustomer(id: Integer);' + sLineBreak +
'function %0:s.DeletePerson(ID: Integer): TMVCResponse;' + sLineBreak +
'begin' + sLineBreak +
' //todo: delete customer by id' + sLineBreak +
'end;' + sLineBreak + sLineBreak;
' LogI(''Deleted person with id '' + ID.ToString);' + sLineBreak +
' Result := TMVCResponse.Create(HTTP_STATUS.OK, ''Person deleted'');' + sLineBreak +
'end;' + sLineBreak;
sActionFiltersIntf =
' protected' + sLineBreak +
@ -242,6 +269,30 @@ resourcestring
' inherited;' + sLineBreak +
'end;' + sLineBreak;
sBOClassesIntf =
' [MVCNameCase(ncCamelCase)]' + sLineBreak +
' TPerson = class' + sLineBreak +
' private' + sLineBreak +
' fFirstName: String;' + sLineBreak +
' fLastName: String;' + sLineBreak +
' fDOB: TDate;' + sLineBreak +
' public' + sLineBreak +
' property FirstName: String read fFirstName write fFirstName;' + sLineBreak +
' property LastName: String read fLastName write fLastName;' + sLineBreak +
' property DOB: TDate read fDOB write fDOB; ' + sLineBreak +
' constructor Create(FirstName, LastName: String; DOB: TDate);' + sLineBreak +
' end;' + sLineBreak;
sBOClassesImpl =
sLineBreak +
'constructor %0:s.Create(FirstName, LastName: String; DOB: TDate);' + sLineBreak +
'begin' + sLineBreak +
' inherited Create;' + sLineBreak +
' fFirstName := FirstName;' + sLineBreak +
' fLastName := LastName;' + sLineBreak +
' fDOB := DOB;' + sLineBreak +
'end;' + sLineBreak;
sDefaultControllerName = 'TMyController';
sDefaultWebModuleName = 'TMyWebModule';
sDefaultServerPort = '8080';

View File

@ -94,7 +94,7 @@ begin
JSONRPCUnitCreator: IOTACreator;
WebModuleCreator: IOTAModuleCreator;
lProjectSourceCreator: IOTACreator;
lJSONRPCUnitName: string;
lJSONRPCUnitName: string;
begin
WizardForm := TfrmDMVCNewProject.Create(Application);
try

View File

@ -358,6 +358,7 @@ function GetDefaultFormatSettings: TFormatSettings;
begin
Result.DateSeparator := '-';
Result.TimeSeparator := ':';
Result.DecimalSeparator := '.';
Result.ShortDateFormat := 'YYYY-MM-DD HH:NN:SS:ZZZ';
Result.ShortTimeFormat := 'HH:NN:SS';
end;

View File

@ -26,6 +26,7 @@ package SwagDoc;
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'SwagDoc Library'}
{$LIBSUFFIX '113'}
{$RUNONLY}
{$IMPLICITBUILD OFF}

View File

@ -97,6 +97,7 @@
<VerInfo_Release>0</VerInfo_Release>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DllSuffix>113</DllSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>

View File

@ -1,58 +0,0 @@
package dmvcframeworkDT;
{$R *.res}
{$R *.dres}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO OFF}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'DelphiMVCFramework 3.x - Design Time Support'}
{$LIBSUFFIX '111'}
{$IMPLICITBUILD ON}
requires
rtl,
designide,
ExpertsCreators,
IndySystem,
IndyProtocols,
IndyCore,
dbrtl,
dmvcframeworkRT;
contains
DMVC.Expert.CodeGen.NewControllerUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas',
DMVC.Expert.CodeGen.NewDMVCProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas',
DMVC.Expert.CodeGen.NewProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas',
DMVC.Expert.CodeGen.NewUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas',
DMVC.Expert.CodeGen.NewWebModuleUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas',
DMVC.Expert.CodeGen.SourceFile in '..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas',
DMVC.Expert.CodeGen.Templates in '..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas',
DMVC.Expert.Forms.NewProjectWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas' {frmDMVCNewProject},
DMVC.Expert.Forms.NewUnitWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas' {frmDMVCNewUnit},
DMVC.Expert.NewUnitWizardEx in '..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas',
DMVC.Expert.ProjectWizardEx in '..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas',
DMVC.Expert.Registration in '..\..\ideexpert\DMVC.Expert.Registration.pas',
DMVC.Splash.Registration in '..\..\ideexpert\DMVC.Splash.Registration.pas';
end.

View File

@ -1,120 +0,0 @@
package dmvcframeworkRT;
{$R *.res}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO OFF}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'DMVCFramework - CopyRight (2010-2023) Daniele Teti and the DMVCFramework Team'}
{$LIBSUFFIX '111'}
{$RUNONLY}
{$IMPLICITBUILD ON}
requires
rtl,
inet,
FireDAC,
IndyCore,
IndyProtocols,
FireDACIBDriver,
FireDACMySQLDriver,
loggerproRT,
FireDACPgDriver,
FireDACSqliteDriver,
SwagDoc;
contains
Web.HTTPDImpl,
Web.ApacheConst,
Web.ApacheHTTP,
Web.Win.IsapiHTTP,
Web.HTTPDMethods,
MVCFramework in '..\..\sources\MVCFramework.pas',
MVCFramework.AsyncTask in '..\..\sources\MVCFramework.AsyncTask.pas',
MVCFramework.Middleware.Swagger in '..\..\sources\MVCFramework.Middleware.Swagger.pas',
MVCFramework.Middleware.Trace in '..\..\sources\MVCFramework.Middleware.Trace.pas',
MVCFramework.Middleware.ETag in '..\..\sources\MVCFramework.Middleware.ETag.pas',
MVCFramework.ActiveRecord in '..\..\sources\MVCFramework.ActiveRecord.pas',
MVCFramework.ActiveRecordController in '..\..\sources\MVCFramework.ActiveRecordController.pas',
MVCFramework.ApplicationSession in '..\..\sources\MVCFramework.ApplicationSession.pas',
MVCFramework.Cache in '..\..\sources\MVCFramework.Cache.pas',
MVCFramework.Commons in '..\..\sources\MVCFramework.Commons.pas',
MVCFramework.Console in '..\..\sources\MVCFramework.Console.pas',
MVCFramework.DataSet.Utils in '..\..\sources\MVCFramework.DataSet.Utils.pas',
MVCFramework.DuckTyping in '..\..\sources\MVCFramework.DuckTyping.pas',
MVCFramework.FireDAC.Utils in '..\..\sources\MVCFramework.FireDAC.Utils.pas',
MVCFramework.HMAC in '..\..\sources\MVCFramework.HMAC.pas',
MVCFramework.JSONRPC.Client in '..\..\sources\MVCFramework.JSONRPC.Client.pas',
MVCFramework.JSONRPC in '..\..\sources\MVCFramework.JSONRPC.pas',
MVCFramework.JWT in '..\..\sources\MVCFramework.JWT.pas',
MVCFramework.Logger in '..\..\sources\MVCFramework.Logger.pas',
MVCFramework.Middleware.Analytics in '..\..\sources\MVCFramework.Middleware.Analytics.pas',
MVCFramework.Middleware.Authentication in '..\..\sources\MVCFramework.Middleware.Authentication.pas',
MVCFramework.Middleware.Authentication.RoleBasedAuthHandler in '..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas',
MVCFramework.Middleware.Compression in '..\..\sources\MVCFramework.Middleware.Compression.pas',
MVCFramework.Middleware.CORS in '..\..\sources\MVCFramework.Middleware.CORS.pas',
MVCFramework.Middleware.JWT in '..\..\sources\MVCFramework.Middleware.JWT.pas',
MVCFramework.Middleware.SecurityHeaders in '..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas',
MVCFramework.MultiMap in '..\..\sources\MVCFramework.MultiMap.pas',
MVCFramework.Patches in '..\..\sources\MVCFramework.Patches.pas',
MVCFramework.RESTAdapter in '..\..\sources\MVCFramework.RESTAdapter.pas',
MVCFramework.Router in '..\..\sources\MVCFramework.Router.pas',
MVCFramework.RQL.AST2FirebirdSQL in '..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas',
MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas',
MVCFramework.RQL.AST2MySQL in '..\..\sources\MVCFramework.RQL.AST2MySQL.pas',
MVCFramework.RQL.AST2PostgreSQL in '..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas',
MVCFramework.RQL.AST2SQLite in '..\..\sources\MVCFramework.RQL.AST2SQLite.pas',
MVCFramework.RQL.Parser in '..\..\sources\MVCFramework.RQL.Parser.pas',
MVCFramework.Rtti.Utils in '..\..\sources\MVCFramework.Rtti.Utils.pas',
MVCFramework.Serializer.Abstract in '..\..\sources\MVCFramework.Serializer.Abstract.pas',
MVCFramework.Serializer.Commons in '..\..\sources\MVCFramework.Serializer.Commons.pas',
MVCFramework.Serializer.Defaults in '..\..\sources\MVCFramework.Serializer.Defaults.pas',
MVCFramework.Serializer.Intf in '..\..\sources\MVCFramework.Serializer.Intf.pas',
MVCFramework.Serializer.JsonDataObjects.CustomTypes in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas',
MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas',
MVCFramework.Session in '..\..\sources\MVCFramework.Session.pas',
MVCFramework.SysControllers in '..\..\sources\MVCFramework.SysControllers.pas',
MVCFramework.SystemJSONUtils in '..\..\sources\MVCFramework.SystemJSONUtils.pas',
MVCFramework.View.Cache in '..\..\sources\MVCFramework.View.Cache.pas',
MVCFramework.Controllers.Register in '..\..\sources\MVCFramework.Controllers.Register.pas',
MVCFramework.SQLGenerators.Firebird in '..\..\sources\MVCFramework.SQLGenerators.Firebird.pas',
MVCFramework.SQLGenerators.Interbase in '..\..\sources\MVCFramework.SQLGenerators.Interbase.pas',
MVCFramework.SQLGenerators.MySQL in '..\..\sources\MVCFramework.SQLGenerators.MySQL.pas',
MVCFramework.SQLGenerators.PostgreSQL in '..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas',
MVCFramework.SQLGenerators.Sqlite in '..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas',
MVCFramework.Swagger.Commons in '..\..\sources\MVCFramework.Swagger.Commons.pas',
MVCFramework.Nullables in '..\..\sources\MVCFramework.Nullables.pas',
MVCFramework.Serializer.HTML in '..\..\sources\MVCFramework.Serializer.HTML.pas',
MVCFramework.LRUCache in '..\..\sources\MVCFramework.LRUCache.pas',
MVCFramework.RESTClient.Commons in '..\..\sources\MVCFramework.RESTClient.Commons.pas',
MVCFramework.RESTClient.Indy in '..\..\sources\MVCFramework.RESTClient.Indy.pas',
MVCFramework.RESTClient.Intf in '..\..\sources\MVCFramework.RESTClient.Intf.pas',
MVCFramework.RESTClient in '..\..\sources\MVCFramework.RESTClient.pas',
MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas',
JsonDataObjects in '..\..\sources\JsonDataObjects.pas';
end.

View File

@ -1,72 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{EA879EE4-1245-4456-AED9-57FDF63577E6}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="..\..\lib\swagdoc\Source\SwagDoc.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj">
<Dependencies/>
</Projects>
<Projects Include="dmvcframeworkRT.dproj">
<Dependencies>..\..\lib\loggerpro\packages\d111\loggerproRT.dproj</Dependencies>
</Projects>
<Projects Include="dmvcframeworkDT.dproj">
<Dependencies>dmvcframeworkRT.dproj</Dependencies>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="SwagDoc">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj"/>
</Target>
<Target Name="SwagDoc:Clean">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj" Targets="Clean"/>
</Target>
<Target Name="SwagDoc:Make">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj" Targets="Make"/>
</Target>
<Target Name="loggerproRT">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj"/>
</Target>
<Target Name="loggerproRT:Clean">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj" Targets="Clean"/>
</Target>
<Target Name="loggerproRT:Make">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj" Targets="Make"/>
</Target>
<Target Name="dmvcframeworkRT" DependsOnTargets="loggerproRT">
<MSBuild Projects="dmvcframeworkRT.dproj"/>
</Target>
<Target Name="dmvcframeworkRT:Clean" DependsOnTargets="loggerproRT:Clean">
<MSBuild Projects="dmvcframeworkRT.dproj" Targets="Clean"/>
</Target>
<Target Name="dmvcframeworkRT:Make" DependsOnTargets="loggerproRT:Make">
<MSBuild Projects="dmvcframeworkRT.dproj" Targets="Make"/>
</Target>
<Target Name="dmvcframeworkDT" DependsOnTargets="dmvcframeworkRT">
<MSBuild Projects="dmvcframeworkDT.dproj"/>
</Target>
<Target Name="dmvcframeworkDT:Clean" DependsOnTargets="dmvcframeworkRT:Clean">
<MSBuild Projects="dmvcframeworkDT.dproj" Targets="Clean"/>
</Target>
<Target Name="dmvcframeworkDT:Make" DependsOnTargets="dmvcframeworkRT:Make">
<MSBuild Projects="dmvcframeworkDT.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="SwagDoc;loggerproRT;dmvcframeworkRT;dmvcframeworkDT"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="SwagDoc:Clean;loggerproRT:Clean;dmvcframeworkRT:Clean;dmvcframeworkDT:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="SwagDoc:Make;loggerproRT:Make;dmvcframeworkRT:Make;dmvcframeworkDT:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@ -1,58 +0,0 @@
package dmvcframeworkDT;
{$R *.res}
{$R *.dres}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO OFF}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'DelphiMVCFramework 3.x - Design Time Support'}
{$LIBSUFFIX '112'}
{$IMPLICITBUILD ON}
requires
rtl,
designide,
ExpertsCreators,
IndySystem,
IndyProtocols,
IndyCore,
dbrtl,
dmvcframeworkRT;
contains
DMVC.Expert.CodeGen.NewControllerUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas',
DMVC.Expert.CodeGen.NewDMVCProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas',
DMVC.Expert.CodeGen.NewProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas',
DMVC.Expert.CodeGen.NewUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas',
DMVC.Expert.CodeGen.NewWebModuleUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas',
DMVC.Expert.CodeGen.SourceFile in '..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas',
DMVC.Expert.CodeGen.Templates in '..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas',
DMVC.Expert.Forms.NewProjectWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas' {frmDMVCNewProject},
DMVC.Expert.Forms.NewUnitWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas' {frmDMVCNewUnit},
DMVC.Expert.NewUnitWizardEx in '..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas',
DMVC.Expert.ProjectWizardEx in '..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas',
DMVC.Expert.Registration in '..\..\ideexpert\DMVC.Expert.Registration.pas',
DMVC.Splash.Registration in '..\..\ideexpert\DMVC.Splash.Registration.pas';
end.

View File

@ -1,120 +0,0 @@
package dmvcframeworkRT;
{$R *.res}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO OFF}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'DMVCFramework - CopyRight (2010-2023) Daniele Teti and the DMVCFramework Team'}
{$LIBSUFFIX '112'}
{$RUNONLY}
{$IMPLICITBUILD ON}
requires
rtl,
inet,
FireDAC,
IndyCore,
IndyProtocols,
FireDACIBDriver,
FireDACMySQLDriver,
loggerproRT,
FireDACPgDriver,
FireDACSqliteDriver,
SwagDoc;
contains
Web.HTTPDImpl,
Web.ApacheConst,
Web.ApacheHTTP,
Web.Win.IsapiHTTP,
Web.HTTPDMethods,
MVCFramework in '..\..\sources\MVCFramework.pas',
MVCFramework.AsyncTask in '..\..\sources\MVCFramework.AsyncTask.pas',
MVCFramework.Middleware.Swagger in '..\..\sources\MVCFramework.Middleware.Swagger.pas',
MVCFramework.Middleware.Trace in '..\..\sources\MVCFramework.Middleware.Trace.pas',
MVCFramework.Middleware.ETag in '..\..\sources\MVCFramework.Middleware.ETag.pas',
MVCFramework.ActiveRecord in '..\..\sources\MVCFramework.ActiveRecord.pas',
MVCFramework.ActiveRecordController in '..\..\sources\MVCFramework.ActiveRecordController.pas',
MVCFramework.ApplicationSession in '..\..\sources\MVCFramework.ApplicationSession.pas',
MVCFramework.Cache in '..\..\sources\MVCFramework.Cache.pas',
MVCFramework.Commons in '..\..\sources\MVCFramework.Commons.pas',
MVCFramework.Console in '..\..\sources\MVCFramework.Console.pas',
MVCFramework.DataSet.Utils in '..\..\sources\MVCFramework.DataSet.Utils.pas',
MVCFramework.DuckTyping in '..\..\sources\MVCFramework.DuckTyping.pas',
MVCFramework.FireDAC.Utils in '..\..\sources\MVCFramework.FireDAC.Utils.pas',
MVCFramework.HMAC in '..\..\sources\MVCFramework.HMAC.pas',
MVCFramework.JSONRPC.Client in '..\..\sources\MVCFramework.JSONRPC.Client.pas',
MVCFramework.JSONRPC in '..\..\sources\MVCFramework.JSONRPC.pas',
MVCFramework.JWT in '..\..\sources\MVCFramework.JWT.pas',
MVCFramework.Logger in '..\..\sources\MVCFramework.Logger.pas',
MVCFramework.Middleware.Analytics in '..\..\sources\MVCFramework.Middleware.Analytics.pas',
MVCFramework.Middleware.Authentication in '..\..\sources\MVCFramework.Middleware.Authentication.pas',
MVCFramework.Middleware.Authentication.RoleBasedAuthHandler in '..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas',
MVCFramework.Middleware.Compression in '..\..\sources\MVCFramework.Middleware.Compression.pas',
MVCFramework.Middleware.CORS in '..\..\sources\MVCFramework.Middleware.CORS.pas',
MVCFramework.Middleware.JWT in '..\..\sources\MVCFramework.Middleware.JWT.pas',
MVCFramework.Middleware.SecurityHeaders in '..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas',
MVCFramework.MultiMap in '..\..\sources\MVCFramework.MultiMap.pas',
MVCFramework.Patches in '..\..\sources\MVCFramework.Patches.pas',
MVCFramework.RESTAdapter in '..\..\sources\MVCFramework.RESTAdapter.pas',
MVCFramework.Router in '..\..\sources\MVCFramework.Router.pas',
MVCFramework.RQL.AST2FirebirdSQL in '..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas',
MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas',
MVCFramework.RQL.AST2MySQL in '..\..\sources\MVCFramework.RQL.AST2MySQL.pas',
MVCFramework.RQL.AST2PostgreSQL in '..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas',
MVCFramework.RQL.AST2SQLite in '..\..\sources\MVCFramework.RQL.AST2SQLite.pas',
MVCFramework.RQL.Parser in '..\..\sources\MVCFramework.RQL.Parser.pas',
MVCFramework.Rtti.Utils in '..\..\sources\MVCFramework.Rtti.Utils.pas',
MVCFramework.Serializer.Abstract in '..\..\sources\MVCFramework.Serializer.Abstract.pas',
MVCFramework.Serializer.Commons in '..\..\sources\MVCFramework.Serializer.Commons.pas',
MVCFramework.Serializer.Defaults in '..\..\sources\MVCFramework.Serializer.Defaults.pas',
MVCFramework.Serializer.Intf in '..\..\sources\MVCFramework.Serializer.Intf.pas',
MVCFramework.Serializer.JsonDataObjects.CustomTypes in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas',
MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas',
MVCFramework.Session in '..\..\sources\MVCFramework.Session.pas',
MVCFramework.SysControllers in '..\..\sources\MVCFramework.SysControllers.pas',
MVCFramework.SystemJSONUtils in '..\..\sources\MVCFramework.SystemJSONUtils.pas',
MVCFramework.View.Cache in '..\..\sources\MVCFramework.View.Cache.pas',
MVCFramework.Controllers.Register in '..\..\sources\MVCFramework.Controllers.Register.pas',
MVCFramework.SQLGenerators.Firebird in '..\..\sources\MVCFramework.SQLGenerators.Firebird.pas',
MVCFramework.SQLGenerators.Interbase in '..\..\sources\MVCFramework.SQLGenerators.Interbase.pas',
MVCFramework.SQLGenerators.MySQL in '..\..\sources\MVCFramework.SQLGenerators.MySQL.pas',
MVCFramework.SQLGenerators.PostgreSQL in '..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas',
MVCFramework.SQLGenerators.Sqlite in '..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas',
MVCFramework.Swagger.Commons in '..\..\sources\MVCFramework.Swagger.Commons.pas',
MVCFramework.Nullables in '..\..\sources\MVCFramework.Nullables.pas',
MVCFramework.Serializer.HTML in '..\..\sources\MVCFramework.Serializer.HTML.pas',
MVCFramework.LRUCache in '..\..\sources\MVCFramework.LRUCache.pas',
MVCFramework.RESTClient.Commons in '..\..\sources\MVCFramework.RESTClient.Commons.pas',
MVCFramework.RESTClient.Indy in '..\..\sources\MVCFramework.RESTClient.Indy.pas',
MVCFramework.RESTClient.Intf in '..\..\sources\MVCFramework.RESTClient.Intf.pas',
MVCFramework.RESTClient in '..\..\sources\MVCFramework.RESTClient.pas',
MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas',
JsonDataObjects in '..\..\sources\JsonDataObjects.pas';
end.

View File

@ -1,72 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{EA879EE4-1245-4456-AED9-57FDF63577E6}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="..\..\lib\swagdoc\Source\SwagDoc.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj">
<Dependencies/>
</Projects>
<Projects Include="dmvcframeworkRT.dproj">
<Dependencies>..\..\lib\loggerpro\packages\d111\loggerproRT.dproj</Dependencies>
</Projects>
<Projects Include="dmvcframeworkDT.dproj">
<Dependencies>dmvcframeworkRT.dproj</Dependencies>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="SwagDoc">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj"/>
</Target>
<Target Name="SwagDoc:Clean">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj" Targets="Clean"/>
</Target>
<Target Name="SwagDoc:Make">
<MSBuild Projects="..\..\lib\swagdoc\Source\SwagDoc.dproj" Targets="Make"/>
</Target>
<Target Name="loggerproRT">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj"/>
</Target>
<Target Name="loggerproRT:Clean">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj" Targets="Clean"/>
</Target>
<Target Name="loggerproRT:Make">
<MSBuild Projects="..\..\lib\loggerpro\packages\d111\loggerproRT.dproj" Targets="Make"/>
</Target>
<Target Name="dmvcframeworkRT" DependsOnTargets="loggerproRT">
<MSBuild Projects="dmvcframeworkRT.dproj"/>
</Target>
<Target Name="dmvcframeworkRT:Clean" DependsOnTargets="loggerproRT:Clean">
<MSBuild Projects="dmvcframeworkRT.dproj" Targets="Clean"/>
</Target>
<Target Name="dmvcframeworkRT:Make" DependsOnTargets="loggerproRT:Make">
<MSBuild Projects="dmvcframeworkRT.dproj" Targets="Make"/>
</Target>
<Target Name="dmvcframeworkDT" DependsOnTargets="dmvcframeworkRT">
<MSBuild Projects="dmvcframeworkDT.dproj"/>
</Target>
<Target Name="dmvcframeworkDT:Clean" DependsOnTargets="dmvcframeworkRT:Clean">
<MSBuild Projects="dmvcframeworkDT.dproj" Targets="Clean"/>
</Target>
<Target Name="dmvcframeworkDT:Make" DependsOnTargets="dmvcframeworkRT:Make">
<MSBuild Projects="dmvcframeworkDT.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="SwagDoc;loggerproRT;dmvcframeworkRT;dmvcframeworkDT"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="SwagDoc:Clean;loggerproRT:Clean;dmvcframeworkRT:Clean;dmvcframeworkDT:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="SwagDoc:Make;loggerproRT:Make;dmvcframeworkRT:Make;dmvcframeworkDT:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@ -1,22 +1,28 @@
library isapiapp;
uses
Winapi.ActiveX,
System.Win.ComObj,
MVCFramework.DotEnv,
MVCFramework.Commons,
MVCFramework.Logger,
Web.WebBroker,
Web.Win.ISAPIApp,
Web.Win.ISAPIThreadPool,
MainDataModuleUnit in '..\..\WineCellarSample\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule},
MainWebModuleUnit in '..\..\WineCellarSample\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule},
WinesBO in '..\..\WineCellarSample\winecellarserver\WinesBO.pas',
WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas';
WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas',
Winapi.Windows;
{$R *.res}
function TerminateExtension(dwFlags: DWORD): BOOL; stdcall;
begin
ReleaseGlobalLogger;
Result := Web.Win.ISAPIThreadPool.TerminateExtension(dwFlags);
end;
exports
GetExtensionVersion,
HttpExtensionProc,
@ -26,5 +32,19 @@ begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
Application.WebModuleClass := WebModuleClass;
dotEnvConfigure(
function: IMVCDotEnv
begin
Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod)
.UseLogger(procedure(LogItem: String)
begin
LogW('dotEnv: ' + LogItem);
end)
.Build(); //uses the executable folder to look for .env* files
end);
Application.Run;
end.

View File

@ -6,8 +6,8 @@
<MainSource>isapiapp.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<TargetedPlatforms>2</TargetedPlatforms>
<AppType>Library</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
@ -34,6 +34,12 @@
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
<Cfg_1_Win64>true</Cfg_1_Win64>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
@ -66,6 +72,14 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>FireDACSqliteDriver;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;TeeDB;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;DataBindingsVCL;FireDACASADriver;bindcompfmx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;xmlrtl;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_ExeOutput>..\bin</DCC_ExeOutput>
<Manifest_File>(None)</Manifest_File>
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
@ -82,6 +96,15 @@
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<Manifest_File>(None)</Manifest_File>
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
<Debugger_HostApplication>C:\Windows\System32\inetsrv\w3wp.exe</Debugger_HostApplication>
<Debugger_RunParams>-debug</Debugger_RunParams>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
@ -94,12 +117,10 @@
</DelphiCompile>
<DCCReference Include="..\..\WineCellarSample\winecellarserver\MainDataModuleUnit.pas">
<Form>WineCellarDataModule</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="..\..\WineCellarSample\winecellarserver\MainWebModuleUnit.pas">
<Form>wm</Form>
<FormType>dfm</FormType>
<DesignClass>TWebModule</DesignClass>
</DCCReference>
<DCCReference Include="..\..\WineCellarSample\winecellarserver\WinesBO.pas"/>
@ -175,10 +196,10 @@
<Source Name="MainSource">isapiapp.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k240.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp240.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k240.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp240.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k280.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp280.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="4">
@ -579,6 +600,127 @@
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
@ -779,127 +921,6 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
@ -914,8 +935,8 @@
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
<Platform value="Win32">False</Platform>
<Platform value="Win64">True</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>

View File

@ -0,0 +1,48 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{5EA2FE29-4523-4296-8CFA-94B6AC904435}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="ISAPI\isapiapp.dproj">
<Dependencies/>
</Projects>
<Projects Include="StandAlone\ConsoleApp.dproj">
<Dependencies/>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="isapiapp">
<MSBuild Projects="ISAPI\isapiapp.dproj"/>
</Target>
<Target Name="isapiapp:Clean">
<MSBuild Projects="ISAPI\isapiapp.dproj" Targets="Clean"/>
</Target>
<Target Name="isapiapp:Make">
<MSBuild Projects="ISAPI\isapiapp.dproj" Targets="Make"/>
</Target>
<Target Name="ConsoleApp">
<MSBuild Projects="StandAlone\ConsoleApp.dproj"/>
</Target>
<Target Name="ConsoleApp:Clean">
<MSBuild Projects="StandAlone\ConsoleApp.dproj" Targets="Clean"/>
</Target>
<Target Name="ConsoleApp:Make">
<MSBuild Projects="StandAlone\ConsoleApp.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="isapiapp;ConsoleApp"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="isapiapp:Clean;ConsoleApp:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="isapiapp:Make;ConsoleApp:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@ -0,0 +1,65 @@
program ConsoleApp;
{$APPTYPE CONSOLE}
uses
MVCFramework,
MVCFramework.Commons,
MVCFramework.Signal,
MVCFramework.DotEnv,
MVCFramework.Logger,
System.SysUtils,
Winapi.Windows,
IdHTTPWebBrokerBridge,
Web.WebReq,
Web.WebBroker,
WinesBO in '..\..\WineCellarSample\winecellarserver\WinesBO.pas',
WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas',
MainWebModuleUnit in '..\..\WineCellarSample\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule},
MainDataModuleUnit in '..\..\WineCellarSample\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule};
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting HTTP Server or port %d', [APort]));
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.DefaultPort := APort;
LServer.Active := True;
Write('CTRL+C to stop the server');
WaitForTerminationSignal;
EnterInShutdownState;
finally
LServer.Free;
end;
end;
begin
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
dotEnvConfigure(
function: IMVCDotEnv
begin
Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod)
.UseLogger(procedure(LogItem: String)
begin
LogW('dotEnv: ' + LogItem);
end)
.Build(); //uses the executable folder to look for .env* files
end);
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end
end.

View File

@ -1,55 +0,0 @@
program StandAloneServer;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.Windows,
IdHTTPWebBrokerBridge,
Web.WebReq,
Web.WebBroker,
WebModuleU in '..\WebModules\WebModuleU.pas' {WebModule1: TWebModule} ,
RoutingSampleControllerU in '..\Controllers\RoutingSampleControllerU.pas',
BusinessObjectsU in '..\BO\BusinessObjectsU.pas';
{$R *.res}
procedure RunServer(APort: Integer);
var
LInputRecord: TInputRecord;
LEvent: DWord;
LHandle: THandle;
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting HTTP Server or port %d', [APort]));
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.DefaultPort := APort;
LServer.Active := True;
Writeln('Press ESC to stop the server');
LHandle := GetStdHandle(STD_INPUT_HANDLE);
while True do
begin
Win32Check(ReadConsoleInput(LHandle, LInputRecord, 1, LEvent));
if (LInputRecord.EventType = KEY_EVENT) and
LInputRecord.Event.KeyEvent.bKeyDown and
(LInputRecord.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE) then
break;
end;
finally
LServer.Free;
end;
end;
begin
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end
end.

1
samples/ISAPI/bin/.env Normal file
View File

@ -0,0 +1 @@
database.path = C:\DEV\dmvcframework\samples\WineCellarSample\winecellarserver\WINES_FB30.FDB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<remove name="CGI-exe" />
<add name="miaisapi" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\DEV\dmvcframework\samples\ISAPI\bin\isapiapp.dll" resourceType="File" requireAccess="Execute" preCondition="bitness32,winx86_64,winx86_64,winx86_64" />
</handlers>
<directoryBrowse enabled="false" />
<rewrite>
<rules>
<rule name="xxxx">
<match url="MyApp/(.*)" />
<action type="Rewrite" url="MyApp/isapiapp.dll/{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

View File

@ -105,6 +105,12 @@ type
[MVCNameCase(ncLowerCase)]
[MVCTable('customers')]
[MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc', TMVCActiveRecordBackEnd.FirebirdSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc', TMVCActiveRecordBackEnd.PostgreSQL)]
[MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')]
[MVCNamedRQLQuery('RatingLessThanPar', 'lt(rating,%d);sort(+code,-city)')]
[MVCNamedRQLQuery('RatingEqualsToPar', 'eq(rating,%d);sort(+code,-city)')]
TCustomer = class(TCustomEntity)
private
{$IFNDEF USE_SEQUENCES}
@ -406,6 +412,35 @@ type
property Orders: TObjectList<TOrder> read GetOrders;
end;
[MVCNameCase(ncLowerCase)]
[MVCEntityActions([eaRetrieve])]
[MVCNamedSQLQuery('CustomersInTheSameCity',
'SELECT c.id, c.DESCRIPTION, c.city, c.code, c.rating, (SELECT count(*) - 1 FROM customers c2 WHERE c2.CITY = c.CITY) customers_in_the_same_city ' +
'FROM CUSTOMERS c WHERE city IS NOT NULL AND city <> '''' ORDER BY customers_in_the_same_city')]
TCustomerStats = class(TCustomEntity)
private
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
fID: NullableInt64;
[MVCTableField('code')]
fCode: NullableString;
[MVCTableField('description')]
fCompanyName: NullableString;
[MVCTableField('city')]
fCity: string;
[MVCTableField('rating')]
fRating: NullableInt32;
[MVCTableField('customers_in_the_same_city')]
fCustomersInTheSameCity: Int32;
public
property ID: NullableInt64 read fID write fID;
property Code: NullableString read fCode write fCode;
property CompanyName: NullableString read fCompanyName write fCompanyName;
property City: string read fCity write fCity;
property Rating: NullableInt32 read fRating write fRating;
property CustomersInTheSameCity: Int32 read fCustomersInTheSameCity write fCustomersInTheSameCity;
end;
[MVCNameCase(ncLowerCase)]
[MVCTable('customers')]
TCustomerWithLogic = class(TCustomer)

View File

@ -2,62 +2,49 @@ object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'TMVCActiveRecord - ShowCase'
ClientHeight = 1423
ClientWidth = 2760
ClientHeight = 569
ClientWidth = 1104
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -28
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OnDestroy = FormDestroy
OnShow = FormShow
PixelsPerInch = 240
DesignSize = (
2760
1423)
TextHeight = 34
1104
569)
TextHeight = 13
object btnCRUD: TButton
Left = 20
Top = 20
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 8
Width = 121
Height = 33
Caption = 'CRUD'
TabOrder = 0
OnClick = btnCRUDClick
end
object btnSelect: TButton
Left = 20
Top = 605
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 242
Width = 121
Height = 33
Caption = 'Queries'
TabOrder = 1
OnClick = btnSelectClick
end
object Memo1: TMemo
Left = 700
Top = 20
Width = 2040
Height = 1383
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 280
Top = 8
Width = 816
Height = 553
Anchors = [akLeft, akTop, akRight, akBottom]
Ctl3D = True
DoubleBuffered = True
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -33
Font.Height = -13
Font.Name = 'Consolas'
Font.Style = []
ParentCtl3D = False
@ -68,310 +55,236 @@ object MainForm: TMainForm
TabOrder = 2
WantReturns = False
WordWrap = False
ExplicitWidth = 2020
ExplicitHeight = 1381
ExplicitWidth = 812
ExplicitHeight = 552
end
object btnRelations: TButton
Left = 20
Top = 703
Width = 303
Height = 87
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 281
Width = 121
Height = 35
Caption = 'Relations'
TabOrder = 3
OnClick = btnRelationsClick
end
object btnInheritance: TButton
Left = 20
Top = 805
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 322
Width = 121
Height = 34
Caption = 'Inheritance'
TabOrder = 4
OnClick = btnInheritanceClick
end
object btnValidation: TButton
Left = 20
Top = 905
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 362
Width = 121
Height = 34
Caption = 'Validation'
TabOrder = 5
OnClick = btnValidationClick
end
object btnMultiThreading: TButton
Left = 360
Top = 20
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 8
Width = 121
Height = 33
Caption = 'Multi Threading'
TabOrder = 6
OnClick = btnMultiThreadingClick
end
object btnRQL: TButton
Left = 20
Top = 1005
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 402
Width = 121
Height = 34
Caption = 'RQL Query'
TabOrder = 7
OnClick = btnRQLClick
end
object btnReadOnlyFields: TButton
Left = 20
Top = 508
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 203
Width = 121
Height = 33
Caption = 'CRUD With R/O Field'
TabOrder = 8
OnClick = btnReadOnlyFieldsClick
end
object btnNullTest: TButton
Left = 360
Top = 118
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 47
Width = 121
Height = 33
Caption = 'Nullables'
TabOrder = 9
OnClick = btnNullTestClick
end
object btnCRUDNoAutoInc: TButton
Left = 20
Top = 215
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 86
Width = 121
Height = 33
Caption = 'CRUD (no autoinc)'
TabOrder = 10
OnClick = btnCRUDNoAutoIncClick
end
object btnCRUDWithStringPKs: TButton
Left = 20
Top = 313
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 125
Width = 121
Height = 33
Caption = 'CRUD (string pks)'
TabOrder = 11
OnClick = btnCRUDWithStringPKsClick
end
object btnWithSpaces: TButton
Left = 20
Top = 410
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 164
Width = 121
Height = 33
Caption = 'CRUD (entity with spaces)'
TabOrder = 12
WordWrap = True
OnClick = btnWithSpacesClick
end
object btnCountWithRQL: TButton
Left = 360
Top = 215
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 86
Width = 121
Height = 33
Caption = 'Count with RQL'
TabOrder = 13
OnClick = btnCountWithRQLClick
end
object btnReadAndWriteOnly: TButton
Left = 360
Top = 313
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 125
Width = 121
Height = 33
Caption = 'R/O, R/W'
TabOrder = 14
OnClick = btnReadAndWriteOnlyClick
end
object btnClientGeneratedPK: TButton
Left = 360
Top = 410
Width = 303
Height = 83
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 164
Width = 121
Height = 33
Caption = 'Client Generated PKs'
TabOrder = 15
OnClick = btnClientGeneratedPKClick
end
object btnAttributes: TButton
Left = 360
Top = 508
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 203
Width = 121
Height = 33
Caption = 'Attributes'
TabOrder = 16
OnClick = btnAttributesClick
end
object btnJSON_XML_Types: TButton
Left = 360
Top = 605
Width = 303
Height = 88
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 242
Width = 121
Height = 35
Caption = 'JSON && XML'
TabOrder = 17
OnClick = btnJSON_XML_TypesClick
end
object btnMerge: TButton
Left = 360
Top = 708
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 283
Width = 121
Height = 34
Caption = 'Merge'
TabOrder = 18
OnClick = btnMergeClick
end
object btnTableFilter: TButton
Left = 360
Top = 808
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 323
Width = 121
Height = 34
Caption = 'Table Filter'
TabOrder = 19
OnClick = btnTableFilterClick
end
object btnPartitioning: TButton
Left = 360
Top = 908
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 363
Width = 121
Height = 33
Caption = 'Table Partitioning'
TabOrder = 20
OnClick = btnPartitioningClick
end
object btnCRUDWithGUID: TButton
Left = 20
Top = 118
Width = 303
Height = 82
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 47
Width = 121
Height = 33
Caption = 'CRUD (with GUID PK)'
TabOrder = 21
OnClick = btnCRUDWithGUIDClick
end
object btnOOP: TButton
Left = 360
Top = 1005
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 402
Width = 121
Height = 34
Caption = 'OOP with Partitioning and Filtering'
TabOrder = 22
WordWrap = True
OnClick = btnOOPClick
end
object btnReadOnly: TButton
Left = 20
Top = 1105
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 442
Width = 121
Height = 34
Caption = 'Read/Only Entities'
TabOrder = 23
OnClick = btnReadOnlyClick
end
object btnSpeed: TButton
Left = 20
Top = 1205
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 8
Top = 482
Width = 121
Height = 34
Caption = 'Metadata Speed Test'
TabOrder = 24
OnClick = btnSpeedClick
end
object btnRefresh: TButton
Left = 360
Top = 1105
Width = 303
Height = 85
Margins.Left = 8
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
Left = 144
Top = 442
Width = 121
Height = 34
Caption = 'Manual Refresh'
TabOrder = 25
OnClick = btnRefreshClick
end
object btnNamedQuery: TButton
Left = 144
Top = 482
Width = 121
Height = 34
Caption = 'Named Query'
TabOrder = 26
OnClick = btnNamedQueryClick
end
object btnVirtualEntities: TButton
Left = 144
Top = 522
Width = 121
Height = 34
Caption = 'Virtual Entities'
TabOrder = 27
OnClick = btnVirtualEntitiesClick
end
object FDConnection1: TFDConnection
Left = 312
Top = 40

View File

@ -58,6 +58,8 @@ type
btnReadOnly: TButton;
btnSpeed: TButton;
btnRefresh: TButton;
btnNamedQuery: TButton;
btnVirtualEntities: TButton;
procedure btnCRUDClick(Sender: TObject);
procedure btnInheritanceClick(Sender: TObject);
procedure btnMultiThreadingClick(Sender: TObject);
@ -86,6 +88,8 @@ type
procedure btnReadOnlyClick(Sender: TObject);
procedure btnSpeedClick(Sender: TObject);
procedure btnRefreshClick(Sender: TObject);
procedure btnNamedQueryClick(Sender: TObject);
procedure btnVirtualEntitiesClick(Sender: TObject);
private
procedure Log(const Value: string);
procedure LoadCustomers;
@ -649,6 +653,61 @@ begin
'in(City,["Rome","New York","London","Melbourne","Berlin"])').ToString + ' records');
end;
procedure TMainForm.btnNamedQueryClick(Sender: TObject);
begin
Log('** Named SQL Query');
Log('QuerySQL: RatingLessThanPar');
var lCustomers := TMVCActiveRecord.SelectByNamedQuery<TCustomer>('RatingLessThanPar', [4], [ftInteger]);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
Log('QuerySQL: RatingEqualsToPar');
lCustomers := TMVCActiveRecord.SelectByNamedQuery<TCustomer>('RatingEqualsToPar', [3], [ftInteger]);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
Log('** Named RQL Query');
Log('QueryRQL: RatingLessThanPar');
lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('RatingLessThanPar', [4], 1000);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
Log('QueryRQL: RatingEqualsToPar');
lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('RatingEqualsToPar', [3], 1000);
try
for var lCustomer in lCustomers do
begin
Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault]));
end;
finally
lCustomers.Free;
end;
end;
procedure TMainForm.btnNullablesClick(Sender: TObject);
var
lCustomer: TCustomer;
@ -1040,6 +1099,7 @@ var
lItem: TMVCActiveRecord;
lCustomer: TCustomer;
lCustList: TObjectList<TCustomer>;
lRecCount: Integer;
const
cRQL1 = 'in(City,["Rome","London"]);sort(+code);limit(0,50)';
cRQL2 = 'and(eq(City,"Rome"),or(contains(CompanyName,"GAS"),contains(CompanyName,"Motors")))';
@ -1133,6 +1193,114 @@ begin
lList.Free;
end;
//******************************************************
// Using "Load" methods ********************************
//******************************************************
Log('*************************************************');
Log('** RQL Queries Test (using "Load" style methods)');
Log('*************************************************');
Log('>> RQL Query (1) - ' + cRQL1);
lList := TMVCActiveRecordList.Create;
try
TMVCActiveRecord.SelectRQL(TCustomer, cRQL1, 20, lList);
Log(lList.Count.ToString + ' record/s found');
for lItem in lList do
begin
lCustomer := TCustomer(lItem);
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
end;
finally
lList.Free;
end;
Log('>> RQL Query (2) - ' + cRQL2);
lCustList := TObjectList<TCustomer>.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL<TCustomer>(cRQL2, 20, lCustList);
Log(lRecCount.ToString + ' record/s found');
for lCustomer in lCustList do
begin
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
end;
finally
lCustList.Free;
end;
Log('**RQL Query (3) - ' + cRQL2);
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, cRQL2, 20, lList);
Log(lRecCount.ToString + ' record/s found');
for lItem in lList do
begin
lCustomer := TCustomer(lItem);
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
end;
finally
lList.Free;
end;
Log('**RQL Query (4) - <empty> with limit 20');
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 20, lList);
Log(lRecCount.ToString + ' record/s found');
Assert(lRecCount = 20);
Assert(lList.Count = lRecCount);
finally
lList.Free;
end;
Log('**RQL Query (5) - <empty> sort by code with limit 20');
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, 'sort(+code)', 20, lList);
Log(lRecCount.ToString + ' record/s found');
Assert(lRecCount = lList.Count);
Assert(lList.Count = 20);
finally
lList.Free;
end;
Log('**RQL Query (6) - <empty> with limit 10');
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 10, lList);
Log(lList.Count.ToString + ' record/s found');
Assert(lRecCount = lList.Count);
Assert(lList.Count = 10);
finally
lList.Free;
end;
Log('**RQL Query (7) - <empty> with limit 1');
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 1, lList);
Log(lList.Count.ToString + ' record/s found');
Assert(lList.Count = 1);
Assert(lRecCount = lList.Count);
finally
lList.Free;
end;
Log('**RQL Query (8) - <empty> with limit 0');
lList := TMVCActiveRecordList.Create;
try
lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 0, lList);
Log(lList.Count.ToString + ' record/s found');
Assert(lList.Count = 0);
Assert(lRecCount = lList.Count);
finally
lList.Free;
end;
end;
procedure TMainForm.btnSelectClick(Sender: TObject);
@ -1541,6 +1709,24 @@ begin
end;
end;
procedure TMainForm.btnVirtualEntitiesClick(Sender: TObject);
begin
var lCustStats := TMVCActiveRecord.SelectByNamedQuery<TCustomerStats>('CustomersInTheSameCity', [], []);
try
for var lCustomer in lCustStats do
begin
Log(Format('%4d - %8.5s - %s - (%d other customers in the same city)', [
lCustomer.ID.ValueOrDefault,
lCustomer.Code.ValueOrDefault,
lCustomer.CompanyName.ValueOrDefault,
lCustomer.CustomersInTheSameCity
]));
end;
finally
lCustStats.Free;
end;
end;
procedure TMainForm.btnWithSpacesClick(Sender: TObject);
var
lCustomer: TCustomerWithSpaces;

View File

@ -203,7 +203,7 @@ type
TInterfacedPerson = class(TInterfacedObject, IPerson)
private
fName: string;
FDOB: TDate;
fDOB: TDate;
fAge: Integer;
protected
function GetName: string;
@ -213,9 +213,10 @@ type
function GetDOB: TDate;
procedure SetDOB(const Value: TDate);
public
property name: string read GetName write SetName;
property Name: string read GetName write SetName;
property Age: Integer read GetAge write SetAge;
property DOB: TDate read GetDOB write SetDOB;
constructor Create(Name: String; Age: Integer; DOB: TDate); virtual;
end;
//TPeople = class(TObjectList<TPerson>);
@ -651,6 +652,14 @@ end;
{ TInterfacedPerson }
constructor TInterfacedPerson.Create(Name: String; Age: Integer; DOB: TDate);
begin
inherited Create;
fName := Name;
fAge := Age;
fDOB := DOB;
end;
function TInterfacedPerson.GetAge: Integer;
begin
Result := fAge;

View File

@ -7,7 +7,7 @@ CREATE TABLE articles (
CREATE TABLE customers (
id integer GENERATED BY DEFAULT AS IDENTITY,
code varchar(20) NOT NULL,
code varchar(20),
description varchar(200),
city varchar(200),
rating INTEGER,

View File

@ -0,0 +1 @@
{"FDBS":{"Version":16,"Manager":{"UpdatesRegistry":true,"TableList":[{"class":"Table","Name":"FDMemTable1","SourceName":"FDMemTable1","TabID":0,"EnforceConstraints":false,"MinimumCapacity":50,"CheckNotNull":false,"ColumnList":[{"class":"Column","Name":"id","SourceName":"id","SourceID":1,"DataType":"Int64","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OInKey":true,"OriginColName":"id"},{"class":"Column","Name":"last_name","SourceName":"last_name","SourceID":2,"DataType":"WideString","Size":100,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"last_name","SourceSize":100},{"class":"Column","Name":"first_name","SourceName":"first_name","SourceID":3,"DataType":"WideString","Size":100,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"first_name","SourceSize":100},{"class":"Column","Name":"dob","SourceName":"dob","SourceID":4,"DataType":"Date","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"dob"},{"class":"Column","Name":"full_name","SourceName":"full_name","SourceID":5,"DataType":"WideString","Size":80,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"full_name","SourceSize":80},{"class":"Column","Name":"is_male","SourceName":"is_male","SourceID":6,"DataType":"Boolean","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"is_male"},{"class":"Column","Name":"note","SourceName":"note","SourceID":7,"DataType":"WideMemo","Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"note"},{"class":"Column","Name":"photo","SourceName":"photo","SourceID":8,"DataType":"Blob","Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"photo"},{"class":"Column","Name":"person_type","SourceName":"person_type","SourceID":9,"DataType":"WideString","Size":8190,"Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"person_type","SourceSize":8190},{"class":"Column","Name":"salary","SourceName":"salary","SourceID":10,"DataType":"Currency","Precision":19,"Scale":4,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"salary","SourcePrecision":19,"SourceScale":4},{"class":"Column","Name":"annual_bonus","SourceName":"annual_bonus","SourceID":11,"DataType":"Currency","Precision":19,"Scale":4,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"annual_bonus","SourcePrecision":19,"SourceScale":4}],"ConstraintList":[],"ViewList":[],"RowList":[{"RowID":0,"Original":{"id":235,"last_name":"Richards","first_name":"Reed","dob":"19851104","full_name":"Reed Richards","is_male":true,"person_type":"person","photo":""}},{"RowID":1,"Original":{"id":236,"last_name":"Parker","first_name":"Peter","dob":"19851104","full_name":"Peter Parker","is_male":true,"person_type":"employee","salary":2100,"photo":""}},{"RowID":2,"Original":{"id":237,"last_name":"Storm","first_name":"Sue","dob":"19751014","full_name":"Sue Storm","is_male":false,"person_type":"employee","salary":2200,"photo":""}},{"RowID":3,"Original":{"id":238,"last_name":"Banner","first_name":"Bruce","dob":"19751104","full_name":"Bruce Banner","is_male":true,"person_type":"manager","salary":2800,"annual_bonus":5000,"photo":""}}]}],"RelationList":[],"UpdatesJournal":{"SavePoint":4,"Changes":[]}}}}

View File

@ -0,0 +1,246 @@
unit ControllerU;
interface
uses
MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons,
System.Generics.Collections, Data.DB;
type
[MVCNameCase(ncCamelCase)]
TPersonRec = record
FirstName, LastName: String;
Age: Integer;
class function Create: TPersonRec; static;
end;
[MVCNameCase(ncCamelCase)]
TPerson = class
private
fAge: Integer;
fFirstName, fLastName: String;
public
property FirstName: String read fFirstName write fFirstName;
property LastName: String read fLastName write fLastName;
property Age: Integer read fAge write fAge;
constructor Create(FirstName, LastName: String; Age: Integer);
end;
[MVCPath('/api')]
TMyController = class(TMVCController)
public
{ actions returning a simple type }
[MVCPath('/sumsasinteger/($A)/($B)')]
function GetSum(const A, B: Integer): Integer;
[MVCPath('/sumsasfloat/($A)/($B)')]
function GetSumAsFloat(const A, B: Extended): Extended;
{ actions returning records }
[MVCPath('/records/single')]
function GetSingleRecord: TPersonRec;
[MVCPath('/records/multiple')]
function GetMultipleRecords: TArray<TPersonRec>;
{ actions returning objects }
[MVCPath('/objects/single')]
function GetSingleObject: TPerson;
[MVCPath('/objects/multiple')]
function GetMultipleObjects: TObjectList<TPerson>;
{ actions returning datasets }
[MVCPath('/datasets/single')]
function GetSingleDataSet: TDataSet;
[MVCPath('/datasets/multiple')]
function GetMultipleDataSet: TEnumerable<TDataSet>;
[MVCPath('/datasets/multiple2')]
function GetMultipleDataSet2: IMVCObjectDictionary;
{ customize response headers }
[MVCPath('/headers')]
function GetWithCustomHeaders: TObjectList<TPerson>;
{ using IMVCResponse }
[MVCPath('/mvcresponse/message')]
function GetMVCResponseSimple: IMVCResponse;
[MVCPath('/mvcresponse/data')]
function GetMVCResponseWithData: IMVCResponse;
[MVCPath('/mvcresponse/list')]
function GetMVCResponseWithObjectList: IMVCResponse;
[MVCPath('/mvcresponse/dictionary')]
function GetMVCResponseWithObjectDictionary: IMVCResponse;
[MVCPath('/mvcresponse/error')]
function GetMVCErrorResponse: IMVCResponse;
end;
implementation
uses
System.SysUtils, MVCFramework.Logger, System.StrUtils, System.DateUtils,
MainDMU, FireDAC.Comp.Client, MVCFramework.FireDAC.Utils;
{ TMyController }
function TMyController.GetMultipleDataSet: TEnumerable<TDataSet>;
begin
var lDM := TdmMain.Create(nil);
try
lDM.dsPeople.Open;
var lList := TObjectList<TDataSet>.Create;
lList.Add(TFDMemTable.CloneFrom(lDM.dsPeople));
lList.Add(TFDMemTable.CloneFrom(lDM.dsPeople));
Result := lList;
finally
lDM.Free;
end;
end;
function TMyController.GetMultipleDataSet2: IMVCObjectDictionary;
begin
var lDM := TdmMain.Create(nil);
try
lDM.dsPeople.Open;
Result := ObjectDict()
.Add('people1', TFDMemTable.CloneFrom(lDM.dsPeople))
.Add('people2', TFDMemTable.CloneFrom(lDM.dsPeople));
finally
lDM.Free;
end;
end;
function TMyController.GetMultipleObjects: TObjectList<TPerson>;
begin
Result := TObjectList<TPerson>.Create;
Result.Add(TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1))));
Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 10));
Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 20));
end;
function TMyController.GetMultipleRecords: TArray<TPersonRec>;
begin
SetLength(Result, 3);
Result[0] := TPersonRec.Create;
Result[1] := TPersonRec.Create;
Result[2] := TPersonRec.Create;
Inc(Result[1].Age, 10);
Inc(Result[2].Age, 20);
end;
function TMyController.GetMVCErrorResponse: IMVCResponse;
begin
Result := TMVCErrorResponse.Create(500, 'boom');
end;
function TMyController.GetMVCResponseSimple: IMVCResponse;
begin
Result := MVCResponse(HTTP_STATUS.OK, 'My Message', 'My Reason String');
end;
function TMyController.GetMVCResponseWithData: IMVCResponse;
begin
Result := MVCResponse(HTTP_STATUS.OK, TPerson.Create('Daniele','Teti', 99));
end;
function TMyController.GetMVCResponseWithObjectDictionary: IMVCResponse;
begin
Result := MVCResponse(
HTTP_STATUS.OK,
ObjectDict()
.Add('people1', TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
)
.Add('people2', TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
)
);
end;
function TMyController.GetMVCResponseWithObjectList: IMVCResponse;
begin
Result := MVCResponse(
HTTP_STATUS.OK,
TObjectList<TPerson>.Create([
TPerson.Create('Daniele','Teti', 99),
TPerson.Create('Peter','Parker', 25),
TPerson.Create('Bruce','Banner', 45)
])
);
end;
function TMyController.GetSingleDataSet: TDataSet;
begin
var lDM := TdmMain.Create(nil);
try
lDM.dsPeople.Open;
Result := TFDMemTable.CloneFrom(lDM.dsPeople);
finally
lDM.Free;
end;
end;
function TMyController.GetSingleObject: TPerson;
begin
Result := TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1)));
end;
function TMyController.GetSingleRecord: TPersonRec;
begin
Result := TPersonRec.Create;
end;
function TMyController.GetSum(const A, B: Integer): Integer;
begin
Result := A + B;
end;
function TMyController.GetSumAsFloat(const A, B: Extended): Extended;
begin
Result := A + B;
end;
function TMyController.GetWithCustomHeaders: TObjectList<TPerson>;
begin
Result := TObjectList<TPerson>.Create;
Result.Add(TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1))));
Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 10));
Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 20));
{ customize headers }
Context.Response.StatusCode := HTTP_STATUS.PartialContent;
Context.Response.ContentType := TMVCMediaType.APPLICATION_JSON;
Context.Response.SetCustomHeader('X-MYHEADER', 'HELLO WORLD');
end;
{ TPersonRec }
class function TPersonRec.Create: TPersonRec;
begin
Result.FirstName := 'Daniele';
Result.LastName := 'Teti';
Result.Age := YearsBetween(Date, EncodeDateDay(1979, 1));
end;
{ TPerson }
constructor TPerson.Create(FirstName, LastName: String; Age: Integer);
begin
inherited Create;
fFirstName := FirstName;
fLastName := LastName;
fAge := Age;
end;
end.

View File

@ -0,0 +1,101 @@
object dmMain: TdmMain
Height = 162
Width = 312
object dsPeople: TFDMemTable
Active = True
FetchOptions.AssignedValues = [evMode]
FetchOptions.Mode = fmAll
ResourceOptions.AssignedValues = [rvPersistent, rvSilentMode]
ResourceOptions.Persistent = True
ResourceOptions.SilentMode = True
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
Left = 176
Top = 88
Content = {
4144425310000000CA060000FF00010001FF02FF03040016000000460044004D
0065006D005400610062006C0065003100050016000000460044004D0065006D
005400610062006C0065003100060000000000070000080032000000090000FF
0AFF0B04000400000069006400050004000000690064000C00010000000E000D
000F000110000111000112000113000114000115000116000400000069006400
FEFF0B0400120000006C006100730074005F006E0061006D0065000500120000
006C006100730074005F006E0061006D0065000C00020000000E001700180064
0000000F00011000011100011200011300011400011600120000006C00610073
0074005F006E0061006D006500190064000000FEFF0B04001400000066006900
7200730074005F006E0061006D00650005001400000066006900720073007400
5F006E0061006D0065000C00030000000E0017001800640000000F0001100001
110001120001130001140001160014000000660069007200730074005F006E00
61006D006500190064000000FEFF0B04000600000064006F0062000500060000
0064006F0062000C00040000000E001A000F0001100001110001120001130001
14000116000600000064006F006200FEFF0B040012000000660075006C006C00
5F006E0061006D006500050012000000660075006C006C005F006E0061006D00
65000C00050000000E0017001800500000000F00011000011100011200011300
01140001160012000000660075006C006C005F006E0061006D00650019005000
0000FEFF0B04000E000000690073005F006D0061006C00650005000E00000069
0073005F006D0061006C0065000C00060000000E001B000F0001100001110001
12000113000114000116000E000000690073005F006D0061006C006500FEFF0B
0400080000006E006F00740065000500080000006E006F00740065000C000700
00000E001C000F00011000011D00011100011200011300011400011600080000
006E006F0074006500FEFF0B04000A000000700068006F0074006F0005000A00
0000700068006F0074006F000C00080000000E001E000F00011000011D000111
000112000113000114000116000A000000700068006F0074006F00FEFF0B0400
1600000070006500720073006F006E005F007400790070006500050016000000
70006500720073006F006E005F0074007900700065000C00090000000E001700
1800FE1F00000F00011000011D00011100011200011300011400011600160000
0070006500720073006F006E005F0074007900700065001900FE1F0000FEFF0B
04000C000000730061006C0061007200790005000C000000730061006C006100
720079000C000A0000000E001F002000130000002100040000000F0001100001
11000112000113000114000116000C000000730061006C006100720079002200
13000000230004000000FEFF0B04001800000061006E006E00750061006C005F
0062006F006E007500730005001800000061006E006E00750061006C005F0062
006F006E00750073000C000B0000000E001F002000130000002100040000000F
000110000111000112000113000114000116001800000061006E006E00750061
006C005F0062006F006E0075007300220013000000230004000000FEFEFF24FE
FF25FEFF26FF27280000000000FF290000EB0000000000000001001000000052
00690063006800610072006400730002000800000052006500650064000300D5
0F0B0004001A0000005200650065006400200052006900630068006100720064
0073000500FFFF08000C00000070006500720073006F006E00FEFEFF27280001
000000FF290000EC0000000000000001000C0000005000610072006B00650072
0002000A000000500065007400650072000300D50F0B00040018000000500065
0074006500720020005000610072006B00650072000500FFFF08001000000065
006D0070006C006F007900650065000900406F400100000000FEFEFF27280002
000000FF290000ED0000000000000001000A000000530074006F0072006D0002
000600000053007500650003007B010B00040012000000530075006500200053
0074006F0072006D000500000008001000000065006D0070006C006F00790065
006500090080B14F0100000000FEFEFF27280003000000FF290000EE00000000
00000001000C000000420061006E006E006500720002000A0000004200720075
0063006500030090010B00040018000000420072007500630065002000420061
006E006E00650072000500FFFF08000E0000006D0061006E0061006700650072
000900003FAB01000000000A0080F0FA0200000000FEFEFEFEFEFF2AFEFF2B2C
0004000000FF2DFEFEFE0E004D0061006E0061006700650072001E0055007000
6400610074006500730052006500670069007300740072007900120054006100
62006C0065004C006900730074000A005400610062006C00650008004E006100
6D006500140053006F0075007200630065004E0061006D0065000A0054006100
620049004400240045006E0066006F0072006300650043006F006E0073007400
7200610069006E00740073001E004D0069006E0069006D0075006D0043006100
700061006300690074007900180043006800650063006B004E006F0074004E00
75006C006C00140043006F006C0075006D006E004C006900730074000C004300
6F006C0075006D006E00100053006F007500720063006500490044000E006400
740049006E007400360034001000440061007400610054007900700065001400
530065006100720063006800610062006C006500120041006C006C006F007700
4E0075006C006C000800420061007300650014004F0041006C006C006F007700
4E0075006C006C0012004F0049006E0055007000640061007400650010004F00
49006E00570068006500720065000C004F0049006E004B00650079001A004F00
72006900670069006E0043006F006C004E0061006D0065001800640074005700
69006400650053007400720069006E0067000800530069007A00650014005300
6F007500720063006500530069007A0065000C00640074004400610074006500
12006400740042006F006F006C00650061006E00140064007400570069006400
65004D0065006D006F00100042006C006F00620044006100740061000C006400
740042006C006F006200140064007400430075007200720065006E0063007900
120050007200650063006900730069006F006E000A005300630061006C006500
1E0053006F00750072006300650050007200650063006900730069006F006E00
160053006F0075007200630065005300630061006C0065001C0043006F006E00
730074007200610069006E0074004C0069007300740010005600690065007700
4C006900730074000E0052006F0077004C00690073007400060052006F007700
0A0052006F0077004900440010004F0072006900670069006E0061006C001800
520065006C006100740069006F006E004C006900730074001C00550070006400
61007400650073004A006F00750072006E0061006C0012005300610076006500
50006F0069006E0074000E004300680061006E00670065007300}
end
end

View File

@ -0,0 +1,26 @@
unit MainDMU;
interface
uses
System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,
FireDAC.DApt.Intf, FireDAC.Stan.StorageBin, Data.DB, FireDAC.Comp.DataSet,
FireDAC.Comp.Client;
type
TdmMain = class(TDataModule)
dsPeople: TFDMemTable;
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{%CLASSGROUP 'System.Classes.TPersistent'}
{$R *.dfm}
end.

View File

@ -0,0 +1,7 @@
object MyWebModule: TMyWebModule
OnCreate = WebModuleCreate
OnDestroy = WebModuleDestroy
Actions = <>
Height = 230
Width = 415
end

View File

@ -0,0 +1,71 @@
unit WebModuleU;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework;
type
TMyWebModule = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
procedure WebModuleDestroy(Sender: TObject);
private
FMVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TMyWebModule;
implementation
{$R *.dfm}
uses
System.IOUtils,
MVCFramework.Commons,
ControllerU;
procedure TMyWebModule.WebModuleCreate(Sender: TObject);
begin
FMVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
Config.dotEnv := dotEnv;
// session timeout (0 means session cookie)
Config[TMVCConfigKey.SessionTimeout] := dotEnv.Env('dmvc.session_timeout', '0');
//default content-type
Config[TMVCConfigKey.DefaultContentType] := dotEnv.Env('dmvc.default.content_type', TMVCConstants.DEFAULT_CONTENT_TYPE);
//default content charset
Config[TMVCConfigKey.DefaultContentCharset] := dotEnv.Env('dmvc.default.content_charset', TMVCConstants.DEFAULT_CONTENT_CHARSET);
//unhandled actions are permitted?
Config[TMVCConfigKey.AllowUnhandledAction] := dotEnv.Env('dmvc.allow_unhandled_actions', 'false');
//enables or not system controllers loading (available only from localhost requests)
Config[TMVCConfigKey.LoadSystemControllers] := dotEnv.Env('dmvc.load_system_controllers', 'true');
//default view file extension
Config[TMVCConfigKey.DefaultViewFileExtension] := dotEnv.Env('dmvc.default.view_file_extension', 'html');
//view path
Config[TMVCConfigKey.ViewPath] := dotEnv.Env('dmvc.view_path', 'templates');
//Max Record Count for automatic Entities CRUD
Config[TMVCConfigKey.MaxEntitiesRecordCount] := dotEnv.Env('dmvc.max_entities_record_count', IntToStr(TMVCConstants.MAX_RECORD_COUNT));
//Enable Server Signature in response
Config[TMVCConfigKey.ExposeServerSignature] := dotEnv.Env('dmvc.expose_server_signature', 'false');
//Enable X-Powered-By Header in response
Config[TMVCConfigKey.ExposeXPoweredBy] := dotEnv.Env('dmvc.expose_x_powered_by', 'true');
// Max request size in bytes
Config[TMVCConfigKey.MaxRequestSize] := dotEnv.Env('dmvc.max_request_size', IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE));
end);
FMVC.AddController(TMyController);
end;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
FMVC.Free;
end;
end.

View File

@ -0,0 +1,83 @@
program function_actions_showcase;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
MVCFramework,
MVCFramework.Logger,
MVCFramework.DotEnv,
MVCFramework.Commons,
MVCFramework.Signal,
Web.ReqMulti,
Web.WebReq,
Web.WebBroker,
IdContext,
IdHTTPWebBrokerBridge,
ControllerU in 'ControllerU.pas',
WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule},
MainDMU in 'MainDMU.pas' {dmMain: TDataModule};
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION);
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication;
LServer.DefaultPort := APort;
LServer.KeepAlive := True;
LServer.MaxConnections := dotEnv.Env('dmvc.webbroker.max_connections', 0);
LServer.ListenQueue := dotEnv.Env('dmvc.indy.listen_queue', 500);
LServer.Active := True;
WriteLn('Listening on port ', APort);
Write('CTRL+C to shutdown the server');
WaitForTerminationSignal;
EnterInShutdownState;
LServer.Active := False;
finally
LServer.Free;
end;
end;
begin
{ Enable ReportMemoryLeaksOnShutdown during debug }
// ReportMemoryLeaksOnShutdown := True;
IsMultiThread := True;
// DMVCFramework Specific Configuration
// When MVCSerializeNulls = True empty nullables and nil are serialized as json null.
// When MVCSerializeNulls = False empty nullables and nil are not serialized at all.
MVCSerializeNulls := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
dotEnvConfigure(
function: IMVCDotEnv
begin
Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod)
.UseLogger(procedure(LogItem: String)
begin
LogW('dotEnv: ' + LogItem);
end)
.Build(); //uses the executable folder to look for .env* files
end);
WebRequestHandlerProc.MaxConnections := dotEnv.Env('dmvc.handler.max_connections', 1024);
RunServer(dotEnv.Env('dmvc.server.port', 8080));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

View File

@ -1,14 +1,14 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{96D17257-AF74-48CB-9893-7BCCB56A069D}</ProjectGuid>
<MainSource>dmvcframeworkRT.dpk</MainSource>
<ProjectGuid>{84012097-1BD4-41B3-A479-B831D1147725}</ProjectGuid>
<ProjectVersion>19.5</ProjectVersion>
<FrameworkType>None</FrameworkType>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Package</AppType>
<AppType>Console</AppType>
<MainSource>function_actions_showcase.dpr</MainSource>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
@ -23,6 +23,11 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Base)'=='true') or '$(Base_Linux64)'!=''">
<Base_Linux64>true</Base_Linux64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
@ -57,37 +62,34 @@
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<GenDll>true</GenDll>
<GenPackage>true</GenPackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_CBuilderOutput>All</DCC_CBuilderOutput>
<SanitizedProjectName>dmvcframeworkRT</SanitizedProjectName>
<RuntimeOnlyPackage>true</RuntimeOnlyPackage>
<VerInfo_Locale>1040</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DCC_Description>DMVCFramework - CopyRight (2010-2020) Daniele Teti and the DMVCFramework Team</DCC_Description>
<UsingDelphiRTL>true</UsingDelphiRTL>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DMVC);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Framework>VCL;$(DCC_Framework)</DCC_Framework>
<SanitizedProjectName>function_actions_showcase</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;fmxase;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android64)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Linux64)'!=''">
<DCC_UsePackage>DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;dbxcds;emsedge;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;dbexpress;FireDACInfxDriver;Python;inet;DataSnapCommon;dbrtl;FireDACOracleDriver;Skia.Package.FMX;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;dsnapxml;DataSnapClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;xmlrtl;dsnap;CloudService;FireDACDb2Driver;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>RaizeComponentsVcl;JvNet;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;frxe28;frxTee28;bindcompvclwinx;Prometheus.Client.Core;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;JvBands;inetdb;JvAppFrm;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;JclVcl;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;Jcl;JvManagedThreads;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;JvPascalInterpreter;PythonVcl;vcltouch;fmxase;frx28;JvPluginSystem;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;JvDB;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;JvTimeFramework;FireDACMSAccDriver;JvCustom;CustomIPTransport;FireDACMSSQLDriver;JvSystem;SVGIconPackage;DataSnapIndy10ServerTransport;JclDeveloperTools;JvControls;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;JvCrypt;FireDACMongoDBDriver;JvJans;JvMM;IndySystem;JvWizards;frxDB28;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;JvGlobus;vcldb;ibxbindings;IconFontsImageList;JclContainers;SynEditDR;JvPageComps;vclFireDAC;JvCore;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;dmvcframeworkDT;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;JvDotNetCtrls;JvHMI;DBXSybaseASEDriver;JvRuntimeDesign;DBXDb2Driver;JvXPCtrls;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;JvStdCtrls;ibxpress;JvDlgs;JvDocking;bindcompvcl;dsnap;JvPrintPreview;JvCmp;dmvcframeworkRT;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;IconFontsImageListFMX;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_Description>DMVCFramework - CopyRight (2010-2021) Daniele Teti and the DMVCFramework Team</DCC_Description>
<DCC_UsePackage>rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;dmvcframeworkDT;$(DCC_UsePackage)</DCC_UsePackage>
<DllSuffix>110</DllSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UsePackage>RaizeComponentsVcl;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;PythonVcl;vcltouch;fmxase;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;SVGIconPackage;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;ibxbindings;SynEditDR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
@ -96,19 +98,11 @@
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
<DCC_RangeChecking>true</DCC_RangeChecking>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_MapFile>3</DCC_MapFile>
<Debugger_IncludeSystemVars>true</Debugger_IncludeSystemVars>
<DCC_UNSUPPORTED_CONSTRUCT>false</DCC_UNSUPPORTED_CONSTRUCT>
<DCC_RunTimeTypeInfo>true</DCC_RunTimeTypeInfo>
<VerInfo_Keys>CompanyName=Daniele Teti and the DMVCFramework Team;FileDescription=DelphiMVCFramework 3.2.2-nitrogen;FileVersion=3.2.2.0;InternalName=DelphiMVCFramework 3.2.2-nitrogen;LegalCopyright=Daniele Teti and the DMVCFramework Team - Apache License 2;LegalTrademarks=DelphiMVCFramework;OriginalFilename=$(MSBuildProjectName);ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=DelphiMVCFramework;ProductVersion=3.2.2;Comments=</VerInfo_Keys>
<VerInfo_MajorVer>3</VerInfo_MajorVer>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<VerInfo_Release>2</VerInfo_Release>
<DllSuffix>111</DllSuffix>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
@ -120,80 +114,17 @@
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="rtl.dcp"/>
<DCCReference Include="inet.dcp"/>
<DCCReference Include="FireDAC.dcp"/>
<DCCReference Include="IndyCore.dcp"/>
<DCCReference Include="IndyProtocols.dcp"/>
<DCCReference Include="FireDACIBDriver.dcp"/>
<DCCReference Include="FireDACMySQLDriver.dcp"/>
<DCCReference Include="loggerproRT.dcp"/>
<DCCReference Include="FireDACPgDriver.dcp"/>
<DCCReference Include="FireDACSqliteDriver.dcp"/>
<DCCReference Include="SwagDoc.dcp"/>
<DCCReference Include="..\..\sources\MVCFramework.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.AsyncTask.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Swagger.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Trace.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.ETag.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ActiveRecord.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ActiveRecordController.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ApplicationSession.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Cache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Console.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.DataSet.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.DuckTyping.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.FireDAC.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.HMAC.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JSONRPC.Client.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JSONRPC.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JWT.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Logger.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Analytics.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Authentication.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Compression.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.CORS.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.JWT.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.MultiMap.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Patches.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTAdapter.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Router.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2MySQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2SQLite.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.Parser.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Rtti.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Abstract.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Defaults.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Intf.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Session.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SysControllers.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SystemJSONUtils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.View.Cache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Controllers.Register.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Firebird.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Interbase.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.MySQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Swagger.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Nullables.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.HTML.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.LRUCache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Indy.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Intf.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Utils.pas"/>
<DCCReference Include="..\..\sources\JsonDataObjects.pas"/>
<DCCReference Include="ControllerU.pas"/>
<DCCReference Include="WebModuleU.pas">
<Form>MyWebModule</Form>
<FormType>dfm</FormType>
<DesignClass>TWebModule</DesignClass>
</DCCReference>
<DCCReference Include="MainDMU.pas">
<Form>dmMain</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
@ -208,16 +139,12 @@
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Package</Borland.ProjectType>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">dmvcframeworkRT.dpk</Source>
<Source Name="MainSource">function_actions_showcase.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="4">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
@ -230,14 +157,17 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\dmvcframeworkRT111.bpl" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="Win32\Debug\function_actions_showcase.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>function_actions_showcase.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
@ -955,7 +885,6 @@
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>

View File

@ -1,87 +1,87 @@
unit AppControllerU;
interface
uses
MVCFramework,
MVCFramework.Commons,
MVCFramework.Logger,
Web.HTTPApp;
type
[MVCPath('/')]
TApp1MainController = class(TMVCController)
public
[MVCPath('/public')]
[MVCHTTPMethod([httpGET])]
procedure PublicSection;
[MVCPath('/')]
[MVCHTTPMethod([httpGET])]
procedure Index;
end;
[MVCPath('/admin')]
TAdminController = class(TMVCController)
public
[MVCPath('/role1')]
[MVCProduces('text/html')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole1;
[MVCPath('/role1')]
[MVCProduces('application/json')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole1EmittingJSON;
[MVCPath('/role2')]
[MVCProduces('text/html')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole2;
end;
implementation
uses
System.SysUtils;
{ TApp1MainController }
procedure TApp1MainController.Index;
begin
Redirect('/index.html');
end;
procedure TApp1MainController.PublicSection;
begin
Render('This is a public section');
end;
{ TAdminController }
procedure TAdminController.OnlyRole1;
begin
ContentType := TMVCMediaType.TEXT_PLAIN;
ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName +
', now you are a logged user and this is a protected content!');
ResponseStream.AppendLine('As logged user you have the following roles: ' +
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
RenderResponseStream;
end;
procedure TAdminController.OnlyRole1EmittingJSON;
begin
ContentType := TMVCMediaType.APPLICATION_JSON;
Render('This is protected content accessible only by user1: parameter = ' +
Context.Request.Params['par1']);
end;
procedure TAdminController.OnlyRole2;
begin
ContentType := TMVCMediaType.TEXT_PLAIN;
ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName +
', now you are a logged user and this is a protected content!');
ResponseStream.AppendLine('As logged user you have the following roles: ' +
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
RenderResponseStream;
end;
end.
unit AppControllerU;
interface
uses
MVCFramework,
MVCFramework.Commons,
MVCFramework.Logger,
Web.HTTPApp;
type
[MVCPath('/')]
TApp1MainController = class(TMVCController)
public
[MVCPath('/public')]
[MVCHTTPMethod([httpGET])]
procedure PublicSection;
[MVCPath('/')]
[MVCHTTPMethod([httpGET])]
procedure Index;
end;
[MVCPath('/admin')]
TAdminController = class(TMVCController)
public
[MVCPath('/role1')]
[MVCProduces('text/html')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole1;
[MVCPath('/role1')]
[MVCProduces('application/json')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole1EmittingJSON;
[MVCPath('/role2')]
[MVCProduces('text/html')]
[MVCHTTPMethod([httpGET])]
procedure OnlyRole2;
end;
implementation
uses
System.SysUtils;
{ TApp1MainController }
procedure TApp1MainController.Index;
begin
Redirect('/index.html');
end;
procedure TApp1MainController.PublicSection;
begin
Render('This is a public section');
end;
{ TAdminController }
procedure TAdminController.OnlyRole1;
begin
ContentType := TMVCMediaType.TEXT_PLAIN;
ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName +
', now you are a logged user and this is a protected content!');
ResponseStream.AppendLine('As logged user you have the following roles: ' +
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
RenderResponseStream;
end;
procedure TAdminController.OnlyRole1EmittingJSON;
begin
ContentType := TMVCMediaType.APPLICATION_JSON;
Render('This is protected content accessible only by user1: parameter = ' +
Context.Request.Params['par1']);
end;
procedure TAdminController.OnlyRole2;
begin
ContentType := TMVCMediaType.TEXT_PLAIN;
ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName +
', now you are a logged user and this is a protected content!');
ResponseStream.AppendLine('As logged user you have the following roles: ' +
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
RenderResponseStream;
end;
end.

View File

@ -1,53 +1,53 @@
program AuthenticateAuthorize;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
{$IFDEF MSWINDOWS}
Winapi.Windows,
Winapi.ShellAPI,
{$ENDIF}
Web.WebReq,
Web.WebBroker,
IdHTTPWebBrokerBridge,
WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule} ,
AppControllerU in 'AppControllerU.pas',
MVCFramework.Middleware.Authentication
in '..\..\sources\MVCFramework.Middleware.Authentication.pas',
AuthenticationU in 'AuthenticationU.pas';
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting HTTP Server or port %d', [APort]));
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.DefaultPort := APort;
LServer.Active := True;
Writeln('Press RETURN to stop the server');
{$IFDEF MSWINDOWS}
ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/static'), nil, nil, SW_SHOW);
{$ENDIF}
ReadLn;
finally
LServer.Free;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
WebRequestHandlerProc.MaxConnections := 1024;
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end
end.
program AuthenticateAuthorize;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
{$IFDEF MSWINDOWS}
Winapi.Windows,
Winapi.ShellAPI,
{$ENDIF}
Web.WebReq,
Web.WebBroker,
IdHTTPWebBrokerBridge,
WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule} ,
AppControllerU in 'AppControllerU.pas',
MVCFramework.Middleware.Authentication
in '..\..\sources\MVCFramework.Middleware.Authentication.pas',
AuthenticationU in 'AuthenticationU.pas';
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting HTTP Server or port %d', [APort]));
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.DefaultPort := APort;
LServer.Active := True;
Writeln('Press RETURN to stop the server');
{$IFDEF MSWINDOWS}
ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/static'), nil, nil, SW_SHOW);
{$ENDIF}
ReadLn;
finally
LServer.Free;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
WebRequestHandlerProc.MaxConnections := 1024;
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end
end.

View File

@ -1,80 +1,80 @@
unit AuthenticationU;
interface
uses
System.SysUtils, MVCFramework.Commons, System.Generics.Collections,
MVCFramework;
type
TAuthenticationSample = class(TInterfacedObject, IMVCAuthenticationHandler)
protected
procedure OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string;
const ActionName: string; var AuthenticationRequired: Boolean);
procedure OnAuthentication(const AContext: TWebContext; const UserName: string; const Password: string;
UserRoles: System.Generics.Collections.TList<System.string>;
var IsValid: Boolean; const SessionData: TSessionData);
procedure OnAuthorization(const AContext: TWebContext; UserRoles
: System.Generics.Collections.TList<System.string>;
const ControllerQualifiedClassName: string; const ActionName: string;
var IsAuthorized: Boolean);
end;
implementation
{ TMVCAuthorization }
procedure TAuthenticationSample.OnAuthentication(const AContext: TWebContext; const UserName: string;
const Password: string;
UserRoles: System.Generics.Collections.TList<System.string>;
var IsValid: Boolean; const SessionData: TSessionData);
begin
IsValid := UserName.Equals(Password); // hey!, this is just a demo!!!
if IsValid then
begin
if UserName = 'user1' then
begin
UserRoles.Add('role1');
end;
if UserName = 'user2' then
begin
UserRoles.Add('role2');
end;
if UserName = 'user3' then // all the roles
begin
UserRoles.Add('role1');
UserRoles.Add('role2');
end;
end
else
begin
UserRoles.Clear;
end;
end;
procedure TAuthenticationSample.OnAuthorization
(const AContext: TWebContext; UserRoles
: System.Generics.Collections.TList<System.string>;
const ControllerQualifiedClassName: string; const ActionName: string;
var IsAuthorized: Boolean);
begin
IsAuthorized := False;
if ActionName = 'Logout' then
IsAuthorized := True; // you can always call logout
if ActionName = 'OnlyRole2' then
IsAuthorized := UserRoles.Contains('role2');
if ActionName = 'OnlyRole1' then
IsAuthorized := UserRoles.Contains('role1');
if ActionName = 'OnlyRole1EmittingJSON' then
IsAuthorized := UserRoles.Contains('role1');
end;
procedure TAuthenticationSample.OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string;
const ActionName: string; var AuthenticationRequired: Boolean);
begin
AuthenticationRequired := ControllerQualifiedClassName =
'AppControllerU.TAdminController';
end;
end.
unit AuthenticationU;
interface
uses
System.SysUtils, MVCFramework.Commons, System.Generics.Collections,
MVCFramework;
type
TAuthenticationSample = class(TInterfacedObject, IMVCAuthenticationHandler)
protected
procedure OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string;
const ActionName: string; var AuthenticationRequired: Boolean);
procedure OnAuthentication(const AContext: TWebContext; const UserName: string; const Password: string;
UserRoles: System.Generics.Collections.TList<System.string>;
var IsValid: Boolean; const SessionData: TSessionData);
procedure OnAuthorization(const AContext: TWebContext; UserRoles
: System.Generics.Collections.TList<System.string>;
const ControllerQualifiedClassName: string; const ActionName: string;
var IsAuthorized: Boolean);
end;
implementation
{ TMVCAuthorization }
procedure TAuthenticationSample.OnAuthentication(const AContext: TWebContext; const UserName: string;
const Password: string;
UserRoles: System.Generics.Collections.TList<System.string>;
var IsValid: Boolean; const SessionData: TSessionData);
begin
IsValid := UserName.Equals(Password); // hey!, this is just a demo!!!
if IsValid then
begin
if UserName = 'user1' then
begin
UserRoles.Add('role1');
end;
if UserName = 'user2' then
begin
UserRoles.Add('role2');
end;
if UserName = 'user3' then // all the roles
begin
UserRoles.Add('role1');
UserRoles.Add('role2');
end;
end
else
begin
UserRoles.Clear;
end;
end;
procedure TAuthenticationSample.OnAuthorization
(const AContext: TWebContext; UserRoles
: System.Generics.Collections.TList<System.string>;
const ControllerQualifiedClassName: string; const ActionName: string;
var IsAuthorized: Boolean);
begin
IsAuthorized := False;
if ActionName = 'Logout' then
IsAuthorized := True; // you can always call logout
if ActionName = 'OnlyRole2' then
IsAuthorized := UserRoles.Contains('role2');
if ActionName = 'OnlyRole1' then
IsAuthorized := UserRoles.Contains('role1');
if ActionName = 'OnlyRole1EmittingJSON' then
IsAuthorized := UserRoles.Contains('role1');
end;
procedure TAuthenticationSample.OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string;
const ActionName: string; var AuthenticationRequired: Boolean);
begin
AuthenticationRequired := ControllerQualifiedClassName =
'AppControllerU.TAdminController';
end;
end.

View File

@ -1,12 +1,11 @@
object WebModule1: TWebModule1
OldCreateOrder = False
OnCreate = WebModuleCreate
Actions = <
item
Default = True
Name = 'DefaultHandler'
PathInfo = '/'
end>
Height = 230
Width = 415
end
object WebModule1: TWebModule1
OnCreate = WebModuleCreate
Actions = <
item
Default = True
Name = 'DefaultHandler'
PathInfo = '/'
end>
Height = 230
Width = 415
end

View File

@ -1,58 +1,60 @@
unit WebModuleUnit1;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework,
MVCFramework.Commons;
type
TWebModule1 = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
private
MVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TWebModule1;
implementation
{$R *.dfm}
uses
AppControllerU,
System.Generics.Collections,
MVCFramework.Middleware.Authentication,
MVCFramework.Middleware.StaticFiles,
AuthenticationU;
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
MVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
Config[TMVCConfigKey.SessionTimeout] := '30';
Config[TMVCConfigKey.DefaultContentType] := 'text/html';
end);
MVC
.AddController(TApp1MainController)
.AddController(TAdminController)
.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(TAuthenticationSample.Create))
.AddMiddleware(TMVCStaticFilesMiddleware.Create(
'/static', { StaticFilesPath }
'..\..\www', { DocumentRoot }
'index.html',
False { not serving a SPA }
));
end;
end.
unit WebModuleUnit1;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework,
MVCFramework.Commons, FireDAC.Phys.PGDef, FireDAC.Stan.Intf, FireDAC.Phys,
FireDAC.Phys.PG;
type
TWebModule1 = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
private
MVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TWebModule1;
implementation
{$R *.dfm}
uses
AppControllerU,
System.Generics.Collections,
MVCFramework.Middleware.Authentication,
MVCFramework.Middleware.ActiveRecord,
MVCFramework.Middleware.StaticFiles,
AuthenticationU;
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
MVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
Config[TMVCConfigKey.SessionTimeout] := '30';
Config[TMVCConfigKey.DefaultContentType] := 'text/html';
end);
MVC
.AddController(TApp1MainController)
.AddController(TAdminController)
.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(TAuthenticationSample.Create))
.AddMiddleware(TMVCStaticFilesMiddleware.Create(
'/static', { StaticFilesPath }
'www', { DocumentRoot }
'index.html',
False { not serving a SPA }
));
end;
end.

View File

@ -1,18 +1,18 @@
<html>
<body>
<h2>Here's the public and the private sections on this application server</h2>
<ul>
<li><a href="/public">Public section</a></li>
<li><a href="/admin/role1">Private section for role1</a></li>
<li><a href="/admin/role2">Private section for role2</a></li>
</ul>
<p>
The available users are shown below:
<ul>
<li>user1/user1 (role1)</li>
<li>user2/user2 (role2)</li>
<li>user3/user3 (role1, role2)</li>
</ul>
</p>
</body>
<html>
<body>
<h2>Here's the public and the private sections on this application server</h2>
<ul>
<li><a href="/public">Public section</a></li>
<li><a href="/admin/role1">Private section for role1</a></li>
<li><a href="/admin/role2">Private section for role2</a></li>
</ul>
<p>
The available users are shown below:
<ul>
<li>user1/user1 (role1)</li>
<li>user2/user2 (role2)</li>
<li>user3/user3 (role1, role2)</li>
</ul>
</p>
</body>
</html>

View File

@ -0,0 +1,30 @@
unit MainControllerU;
interface
uses
MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons;
type
[MVCPath('/api')]
TMyController = class(TMVCController)
public
[MVCPath('/customers')]
[MVCHTTPMethod([httpPOST])]
procedure CreateCustomer(const [MVCFromBody] Dict: TMVCStringDictionary);
end;
implementation
uses
System.SysUtils, MVCFramework.Logger, System.StrUtils;
procedure TMyController.CreateCustomer(const [MVCFromBody] Dict: TMVCStringDictionary);
begin
Render(
ObjectDict().Add('data', StrDict.Add('message', Dict['hello']))
)
end;
end.

View File

@ -0,0 +1,48 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{9F8DA910-24A1-4497-AAB9-7BDE0D4186C2}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="middleware_cors.dproj">
<Dependencies/>
</Projects>
<Projects Include="SimpleWebServer\SimpleWebServer.dproj">
<Dependencies/>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="middleware_cors">
<MSBuild Projects="middleware_cors.dproj"/>
</Target>
<Target Name="middleware_cors:Clean">
<MSBuild Projects="middleware_cors.dproj" Targets="Clean"/>
</Target>
<Target Name="middleware_cors:Make">
<MSBuild Projects="middleware_cors.dproj" Targets="Make"/>
</Target>
<Target Name="SimpleWebServer">
<MSBuild Projects="SimpleWebServer\SimpleWebServer.dproj"/>
</Target>
<Target Name="SimpleWebServer:Clean">
<MSBuild Projects="SimpleWebServer\SimpleWebServer.dproj" Targets="Clean"/>
</Target>
<Target Name="SimpleWebServer:Make">
<MSBuild Projects="SimpleWebServer\SimpleWebServer.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="middleware_cors;SimpleWebServer"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="middleware_cors:Clean;SimpleWebServer:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="middleware_cors:Make;SimpleWebServer:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@ -0,0 +1,90 @@
program SimpleWebServer;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
WinAPI.ShellAPI,
MVCFramework,
MVCFramework.Logger,
MVCFramework.DotEnv,
MVCFramework.Commons,
MVCFramework.Signal,
Web.ReqMulti,
Web.WebReq,
Web.WebBroker,
IdContext,
IdHTTPWebBrokerBridge,
WebModuleU in 'WebModuleU.pas', Winapi.Windows {MyWebModule: TWebModule};
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION);
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication;
LServer.DefaultPort := APort;
LServer.KeepAlive := True;
LServer.MaxConnections := dotEnv.Env('dmvc.webbroker.max_connections', 0);
LServer.ListenQueue := dotEnv.Env('dmvc.indy.listen_queue', 500);
LServer.Active := True;
{ Comment the next line to avoid the default browser startup }
{$IFDEF MSWINDOWS}
ShellExecute(0, 'open', PChar('http://localhost:' + inttostr(APort)), nil, nil, SW_SHOWMAXIMIZED);
{$ENDIF}
WriteLn('Simple Web Server');
WriteLn('Listening on port ', APort);
Write('CTRL+C to shutdown the server');
WaitForTerminationSignal;
EnterInShutdownState;
LServer.Active := False;
finally
LServer.Free;
end;
end;
begin
{ Enable ReportMemoryLeaksOnShutdown during debug }
// ReportMemoryLeaksOnShutdown := True;
IsMultiThread := True;
// DMVCFramework Specific Configuration
// When MVCSerializeNulls = True empty nullables and nil are serialized as json null.
// When MVCSerializeNulls = False empty nullables and nil are not serialized at all.
MVCSerializeNulls := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
dotEnvConfigure(
function: IMVCDotEnv
begin
Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod)
.UseLogger(procedure(LogItem: String)
begin
LogW('dotEnv: ' + LogItem);
end)
.Build(); //uses the executable folder to look for .env* files
end);
WebRequestHandlerProc.MaxConnections := dotEnv.Env('dmvc.handler.max_connections', 1024);
RunServer(dotEnv.Env('dmvc.server.port', 9090));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

View File

@ -1,14 +1,14 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{96D17257-AF74-48CB-9893-7BCCB56A069D}</ProjectGuid>
<MainSource>dmvcframeworkRT.dpk</MainSource>
<ProjectGuid>{1553C606-62E3-4D67-8E5B-3440886F90A9}</ProjectGuid>
<ProjectVersion>19.5</ProjectVersion>
<FrameworkType>None</FrameworkType>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Package</AppType>
<AppType>Console</AppType>
<MainSource>SimpleWebServer.dpr</MainSource>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
@ -23,6 +23,11 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Base)'=='true') or '$(Base_Linux64)'!=''">
<Base_Linux64>true</Base_Linux64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
@ -51,43 +56,42 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_ExeOutput>..\bin</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<GenDll>true</GenDll>
<GenPackage>true</GenPackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_CBuilderOutput>All</DCC_CBuilderOutput>
<SanitizedProjectName>dmvcframeworkRT</SanitizedProjectName>
<RuntimeOnlyPackage>true</RuntimeOnlyPackage>
<UsingDelphiRTL>true</UsingDelphiRTL>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DMVC);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Framework>VCL;$(DCC_Framework)</DCC_Framework>
<SanitizedProjectName>SimpleWebServer</SanitizedProjectName>
<VerInfo_Locale>1040</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DCC_Description>DMVCFramework - CopyRight (2010-2020) Daniele Teti and the DMVCFramework Team</DCC_Description>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;fmxase;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android64)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Linux64)'!=''">
<DCC_UsePackage>DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;dbxcds;emsedge;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;dbexpress;FireDACInfxDriver;Python;inet;DataSnapCommon;dbrtl;FireDACOracleDriver;Skia.Package.FMX;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;dsnapxml;DataSnapClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;xmlrtl;dsnap;CloudService;FireDACDb2Driver;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>RaizeComponentsVcl;JvNet;vclwinx;DataSnapServer;FixInsight_11;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;frxe28;frxTee28;bindcompvclwinx;Prometheus.Client.Core;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;JvBands;inetdb;JvAppFrm;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;JclVcl;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;Jcl;JvManagedThreads;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;JvPascalInterpreter;PythonVcl;vcltouch;fmxase;frx28;JvPluginSystem;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;JvDB;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;JvTimeFramework;FireDACMSAccDriver;JvCustom;CustomIPTransport;FireDACMSSQLDriver;JvSystem;SVGIconPackage;DataSnapIndy10ServerTransport;JclDeveloperTools;JvControls;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;JvCrypt;FireDACMongoDBDriver;JvJans;JvMM;IndySystem;JvWizards;frxDB28;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;JvGlobus;vcldb;ibxbindings;IconFontsImageList;JclContainers;SynEditDR;JvPageComps;vclFireDAC;JvCore;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;dmvcframeworkDT;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;JvDotNetCtrls;JvHMI;DBXSybaseASEDriver;JvRuntimeDesign;DBXDb2Driver;JvXPCtrls;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;JvStdCtrls;ibxpress;JvDlgs;JvDocking;bindcompvcl;dsnap;JvPrintPreview;JvCmp;dmvcframeworkRT;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;IconFontsImageListFMX;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_Description>DMVCFramework - CopyRight (2010-2021) Daniele Teti and the DMVCFramework Team</DCC_Description>
<DCC_UsePackage>rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;dmvcframeworkDT;$(DCC_UsePackage)</DCC_UsePackage>
<DllSuffix>110</DllSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UsePackage>RaizeComponentsVcl;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;PythonVcl;vcltouch;fmxase;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;SVGIconPackage;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;ibxbindings;SynEditDR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
@ -96,20 +100,14 @@
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
<DCC_RangeChecking>true</DCC_RangeChecking>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_MapFile>3</DCC_MapFile>
<Debugger_IncludeSystemVars>true</Debugger_IncludeSystemVars>
<DCC_UNSUPPORTED_CONSTRUCT>false</DCC_UNSUPPORTED_CONSTRUCT>
<DCC_RunTimeTypeInfo>true</DCC_RunTimeTypeInfo>
<VerInfo_Keys>CompanyName=Daniele Teti and the DMVCFramework Team;FileDescription=DelphiMVCFramework 3.2.2-nitrogen;FileVersion=3.2.2.0;InternalName=DelphiMVCFramework 3.2.2-nitrogen;LegalCopyright=Daniele Teti and the DMVCFramework Team - Apache License 2;LegalTrademarks=DelphiMVCFramework;OriginalFilename=$(MSBuildProjectName);ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=DelphiMVCFramework;ProductVersion=3.2.2;Comments=</VerInfo_Keys>
<VerInfo_MajorVer>3</VerInfo_MajorVer>
<VerInfo_MinorVer>2</VerInfo_MinorVer>
<VerInfo_Release>2</VerInfo_Release>
<DllSuffix>112</DllSuffix>
<DCC_Description>DMVCFramework - CopyRight (2010-2022) Daniele Teti and the DMVCFramework Team</DCC_Description>
<Manifest_File>(None)</Manifest_File>
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
@ -121,74 +119,7 @@
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="rtl.dcp"/>
<DCCReference Include="inet.dcp"/>
<DCCReference Include="FireDAC.dcp"/>
<DCCReference Include="IndyCore.dcp"/>
<DCCReference Include="IndyProtocols.dcp"/>
<DCCReference Include="FireDACIBDriver.dcp"/>
<DCCReference Include="FireDACMySQLDriver.dcp"/>
<DCCReference Include="loggerproRT.dcp"/>
<DCCReference Include="FireDACPgDriver.dcp"/>
<DCCReference Include="FireDACSqliteDriver.dcp"/>
<DCCReference Include="..\..\sources\MVCFramework.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ActiveRecord.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ActiveRecordController.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.ApplicationSession.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Cache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Console.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.DataSet.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.DuckTyping.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.FireDAC.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.HMAC.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JSONRPC.Client.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JSONRPC.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.JWT.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Logger.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Analytics.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Authentication.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.Compression.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.CORS.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.JWT.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.MultiMap.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Patches.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTAdapter.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Router.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2MySQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.AST2SQLite.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RQL.Parser.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Rtti.Utils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Abstract.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Defaults.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.Intf.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Session.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SysControllers.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SystemJSONUtils.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.View.Cache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Controllers.Register.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Firebird.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Interbase.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.MySQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Swagger.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Nullables.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Serializer.HTML.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.LRUCache.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Commons.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Indy.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.Intf.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.RESTClient.pas"/>
<DCCReference Include="..\..\sources\MVCFramework.Utils.pas"/>
<DCCReference Include="WebModuleU.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
@ -203,13 +134,15 @@
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Package</Borland.ProjectType>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">dmvcframeworkRT.dpk</Source>
<Source Name="MainSource">SimpleWebServer.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k280.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp280.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
@ -225,17 +158,14 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\dmvcframeworkRT111.bpl" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\dmvcframeworkRT112.bpl" Configuration="Debug" Class="ProjectOutput">
<DeployFile LocalName="Win32\Debug\SimpleWebServer.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>dmvcframeworkRT.bpl</RemoteName>
<RemoteName>SimpleWebServer.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
@ -630,6 +560,127 @@
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
@ -830,133 +881,11 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>

View File

@ -0,0 +1,7 @@
object MyWebModule: TMyWebModule
OnCreate = WebModuleCreate
OnDestroy = WebModuleDestroy
Actions = <>
Height = 230
Width = 415
end

View File

@ -0,0 +1,125 @@
unit WebModuleU;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework;
type
TMyWebModule = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
procedure WebModuleDestroy(Sender: TObject);
private
FMVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TMyWebModule;
implementation
{$R *.dfm}
uses
System.IOUtils,
MVCFramework.Commons,
MVCFramework.Middleware.ActiveRecord,
MVCFramework.Middleware.StaticFiles,
MVCFramework.Middleware.Analytics,
MVCFramework.Middleware.Redirect,
MVCFramework.Middleware.Trace,
MVCFramework.Middleware.CORS,
MVCFramework.Middleware.ETag,
MVCFramework.Middleware.Compression;
procedure TMyWebModule.WebModuleCreate(Sender: TObject);
begin
FMVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
Config.dotEnv := dotEnv;
// session timeout (0 means session cookie)
Config[TMVCConfigKey.SessionTimeout] := dotEnv.Env('dmvc.session_timeout', '0');
//default content-type
Config[TMVCConfigKey.DefaultContentType] := dotEnv.Env('dmvc.default.content_type', TMVCConstants.DEFAULT_CONTENT_TYPE);
//default content charset
Config[TMVCConfigKey.DefaultContentCharset] := dotEnv.Env('dmvc.default.content_charset', TMVCConstants.DEFAULT_CONTENT_CHARSET);
//unhandled actions are permitted?
Config[TMVCConfigKey.AllowUnhandledAction] := dotEnv.Env('dmvc.allow_unhandled_actions', 'false');
//enables or not system controllers loading (available only from localhost requests)
Config[TMVCConfigKey.LoadSystemControllers] := dotEnv.Env('dmvc.load_system_controllers', 'true');
//default view file extension
Config[TMVCConfigKey.DefaultViewFileExtension] := dotEnv.Env('dmvc.default.view_file_extension', 'html');
//view path
Config[TMVCConfigKey.ViewPath] := dotEnv.Env('dmvc.view_path', 'templates');
//Max Record Count for automatic Entities CRUD
Config[TMVCConfigKey.MaxEntitiesRecordCount] := dotEnv.Env('dmvc.max_entities_record_count', IntToStr(TMVCConstants.MAX_RECORD_COUNT));
//Enable Server Signature in response
Config[TMVCConfigKey.ExposeServerSignature] := dotEnv.Env('dmvc.expose_server_signature', 'false');
//Enable X-Powered-By Header in response
Config[TMVCConfigKey.ExposeXPoweredBy] := dotEnv.Env('dmvc.expose_x_powered_by', 'true');
// Max request size in bytes
Config[TMVCConfigKey.MaxRequestSize] := dotEnv.Env('dmvc.max_request_size', IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE));
end);
// Analytics middleware generates a csv log, useful to do traffic analysis
//FMVC.AddMiddleware(TMVCAnalyticsMiddleware.Create(GetAnalyticsDefaultLogger));
// The folder mapped as documentroot for TMVCStaticFilesMiddleware must exists!
FMVC.AddMiddleware(
TMVCStaticFilesMiddleware.Create(
'/static',
TPath.Combine(ExtractFilePath(GetModuleName(HInstance)), 'www')));
FMVC.AddMiddleware(TMVCRedirectMiddleware.Create(['/'], '/static'));
// Trace middlewares produces a much detailed log for debug purposes
//FMVC.AddMiddleware(TMVCTraceMiddleware.Create);
// CORS middleware handles... well, CORS
//FMVC.AddMiddleware(TMVCCORSMiddleware.Create);
// Simplifies TMVCActiveRecord connection definition
{
FMVC.AddMiddleware(TMVCActiveRecordMiddleware.Create(
dotEnv.Env('firedac.connection_definition_name', 'MyConnDef'),
dotEnv.Env('firedac.connection_definitions_filename', 'FDConnectionDefs.ini')
));
}
// Compression middleware must be the last in the chain, just before the ETag, if present.
//FMVC.AddMiddleware(TMVCCompressionMiddleware.Create);
// ETag middleware must be the latest in the chain
//FMVC.AddMiddleware(TMVCETagMiddleware.Create);
{
FMVC.OnWebContextCreate(
procedure(const Context: TWebContext)
begin
// Initialize services to make them accessibile from Context
// Context.CustomIntfObject := TMyService.Create;
end);
FMVC.OnWebContextDestroy(
procedure(const Context: TWebContext)
begin
//Cleanup services, if needed
end);
}
end;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
FMVC.Free;
end;
end.

View File

@ -0,0 +1,7 @@
object MyWebModule: TMyWebModule
OnCreate = WebModuleCreate
OnDestroy = WebModuleDestroy
Actions = <>
Height = 230
Width = 415
end

View File

@ -0,0 +1,80 @@
unit WebModuleU;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework,
MVCFramework.Logger;
type
TMyWebModule = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
procedure WebModuleDestroy(Sender: TObject);
private
FMVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TMyWebModule;
implementation
{$R *.dfm}
uses
MainControllerU,
System.IOUtils,
MVCFramework.Commons,
MVCFramework.Middleware.StaticFiles,
MVCFramework.Middleware.Redirect,
MVCFramework.Middleware.Compression,
MVCFramework.Middleware.CORS;
procedure TMyWebModule.WebModuleCreate(Sender: TObject);
begin
FMVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
// session timeout (0 means session cookie)
Config[TMVCConfigKey.SessionTimeout] := '0';
// default content-type
Config[TMVCConfigKey.DefaultContentType] := TMVCConstants.DEFAULT_CONTENT_TYPE;
// default content charset
Config[TMVCConfigKey.DefaultContentCharset] := TMVCConstants.DEFAULT_CONTENT_CHARSET;
// unhandled actions are permitted?
Config[TMVCConfigKey.AllowUnhandledAction] := 'false';
// default view file extension
Config[TMVCConfigKey.DefaultViewFileExtension] := 'html';
// view path
Config[TMVCConfigKey.ViewPath] := 'templates';
// Max Record Count for automatic Entities CRUD
Config[TMVCConfigKey.MaxEntitiesRecordCount] := '20';
// Enable Server Signature in response
Config[TMVCConfigKey.ExposeServerSignature] := 'true';
// Max request size in bytes
Config[TMVCConfigKey.MaxRequestSize] := IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE);
Config[TMVCConfigKey.LoadSystemControllers] := 'false';
end);
FMVC
.AddController(TMyController);
{ // Allows all origins -> * }
//FMVC.AddMiddleware(TMVCCORSMiddleware.Create);
{ // Allows all origins -> * }
FMVC.AddMiddleware(TMVCCORSMiddleware.Create('https://anotherserver.com,http://localhost:9090'));
end;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
FMVC.Free;
end;
end.

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>DMVCFramework CORS Sample</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
<button id="btn">Click Here!</button>
<div id="output"></div>
<script defer>
let output = document.getElementById('output');
document.getElementById('btn').onclick = () => {
fetch('http://localhost:8080/api/customers', {
"method": 'POST',
"body": JSON.stringify({ "hello": "world" })
})
.then((res) => res.json())
.then((json) => {
output.innerHTML = json['data']["message"]
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,67 @@
program middleware_cors;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
MVCFramework,
MVCFramework.Logger,
MVCFramework.Commons,
{$IFDEF MSWINDOWS}
Winapi.Windows,
Winapi.ShellAPI,
{$ENDIF }
MVCFramework.Signal,
Web.ReqMulti,
Web.WebReq,
Web.WebBroker,
IdContext,
IdHTTPWebBrokerBridge,
MainControllerU in 'MainControllerU.pas',
WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule};
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION);
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication;
LServer.DefaultPort := APort;
LServer.MaxConnections := 0;
LServer.ListenQueue := 200;
{ required if you use JWT middleware }
LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication;
LServer.Active := True;
WriteLn('Middleware CORS Sample');
WriteLn('Listening on port ', APort);
Write('CTRL+C to shutdown the server');
WaitForTerminationSignal;
EnterInShutdownState;
LServer.Active := False;
finally
LServer.Free;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
IsMultiThread := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
WebRequestHandlerProc.MaxConnections := 1024;
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

View File

@ -1,14 +1,14 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{84344511-1DC2-41BA-8689-9F36C1D475BE}</ProjectGuid>
<MainSource>dmvcframeworkDT.dpk</MainSource>
<ProjectGuid>{A4AB18DC-0F2D-4D2A-94F8-67D871413D88}</ProjectGuid>
<ProjectVersion>19.5</ProjectVersion>
<FrameworkType>None</FrameworkType>
<FrameworkType>VCL</FrameworkType>
<MainSource>middleware_cors.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Package</AppType>
<AppType>Console</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
@ -23,6 +23,11 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Base)'=='true') or '$(Base_Linux64)'!=''">
<Base_Linux64>true</Base_Linux64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
@ -49,12 +54,6 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
@ -63,37 +62,38 @@
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<GenDll>true</GenDll>
<GenPackage>true</GenPackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_CBuilderOutput>All</DCC_CBuilderOutput>
<SanitizedProjectName>dmvcframeworkDT</SanitizedProjectName>
<VerInfo_Locale>1040</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DCC_Description>DelphiMVCFramework IDE Expert</DCC_Description>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<UsingDelphiRTL>true</UsingDelphiRTL>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DMVC);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Framework>VCL;$(DCC_Framework)</DCC_Framework>
<SanitizedProjectName>middleware_cors</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;ibxbindings;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
<Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android64)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;ibxbindings;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
<EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
<Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Linux64)'!=''">
<DCC_UsePackage>RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACADSDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;Spring.Data;inetdb;SMCmpntRX103;emsedge;FireDACIBDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;soapserver;bindengine;CloudService;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndySystem;FireDACDb2Driver;FireDACInfxDriver;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;rtl;emsserverresource;DbxClientDriver;CustomIPTransport;bindcomp;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;dbrtl;IndyProtocols;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;IconFontsImageList;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;Spring.Data;inetdb;SMCmpntRX103;RaizeComponentsVcl;emsedge;RaizeComponentsVclDb;fmx;FireDACIBDriver;fmxdae;RadiantShapesFmx;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python_D;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IconFontsImageListFMX;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;ibxbindings;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dmvcframeworkRT;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;DataSnapIndy10ServerTransport;dmvcframeworkDT;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_UsePackage>rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;dmvcframeworkRT;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UnitSearchPath>..\..\sources;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Description>DelphiMVCFramework 3.x - Design Time Support</DCC_Description>
<DllSuffix>110</DllSuffix>
<DCC_ExeOutput>.\bin</DCC_ExeOutput>
<Manifest_File>(None)</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;Spring.Data;inetdb;RaizeComponentsVcl;emsedge;RaizeComponentsVclDb;fmx;FireDACIBDriver;fmxdae;RadiantShapesFmx;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;ibxbindings;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
@ -105,11 +105,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_UNSUPPORTED_CONSTRUCT>false</DCC_UNSUPPORTED_CONSTRUCT>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=Daniele Teti and the DMVCFramework Team;LegalTrademarks=DelphiMVCFramework;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DllSuffix>112</DllSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
@ -117,51 +113,15 @@
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="rtl.dcp"/>
<DCCReference Include="designide.dcp"/>
<DCCReference Include="ExpertsCreators.dcp"/>
<DCCReference Include="IndySystem.dcp"/>
<DCCReference Include="IndyProtocols.dcp"/>
<DCCReference Include="IndyCore.dcp"/>
<DCCReference Include="dbrtl.dcp"/>
<DCCReference Include="dmvcframeworkRT.dcp"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas">
<Form>frmDMVCNewProject</Form>
<DCCReference Include="MainControllerU.pas"/>
<DCCReference Include="WebModuleU.pas">
<Form>MyWebModule</Form>
<DesignClass>TWebModule</DesignClass>
</DCCReference>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas">
<Form>frmDMVCNewUnit</Form>
</DCCReference>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Registration.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Splash.Registration.pas"/>
<RcItem Include="..\..\ideexpert\DMVC.Expert.NewProject.ico">
<ResourceType>ICON</ResourceType>
<ResourceId>DMVCNewProjectIcon</ResourceId>
</RcItem>
<RcItem Include="..\..\ideexpert\DMVC.Expert.NewUnit.ico">
<ResourceType>ICON</ResourceType>
<ResourceId>DMVCNewUnitIcon</ResourceId>
</RcItem>
<RcItem Include="..\..\ideexpert\SplashScreen.bmp">
<ResourceType>BITMAP</ResourceType>
<ResourceId>SplashScreen</ResourceId>
</RcItem>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
@ -176,37 +136,30 @@
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Package</Borland.ProjectType>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">dmvcframeworkDT.dpk</Source>
<Source Name="MainSource">middleware_cors.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="4">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule"/>
<DeployFile LocalName="bin\middleware_cors.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>middleware_cors.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\dmvcframeworkDT104.bpl" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="bin\middleware_staticfiles.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
@ -598,6 +551,127 @@
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
@ -798,127 +872,6 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>

View File

@ -32,7 +32,9 @@ uses
MVCFramework,
MVCFramework.Commons,
MVCFramework.Serializer.Intf,
System.Rtti, BusinessObjectsU;
System.Rtti,
System.Generics.Collections,
BusinessObjectsU, Data.DB;
type
@ -42,6 +44,18 @@ type
procedure OnBeforeAction(AContext: TWebContext; const AActionName: string;
var AHandled: Boolean); override;
public
// Result BASED
[MVCHTTPMethod([httpGET])]
[MVCPath('/func/people')]
[MVCProduces('application/json')]
function GetPeople_AsObjectList_AsFunction: TEnumerable<TPerson>;
[MVCHTTPMethod([httpGET])]
[MVCPath('/func/customers/simple')]
function GetCustomers_AsDataSet_AsFunction: TDataSet;
// Render BASED
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers/simple')]
procedure GetCustomers_AsDataSet;
@ -266,10 +280,9 @@ uses
InMemoryDataU,
JsonDataObjects,
MVCFramework.Serializer.JsonDataObjects,
Data.DB,
Web.HTTPApp,
Graphics,
System.Types;
System.Types, FireDAC.Comp.Client;
procedure DrawLogo(const Logo: TBitmap);
var
@ -515,6 +528,20 @@ begin
end;
end;
function TRenderSampleController.GetCustomers_AsDataSet_AsFunction: TDataSet;
var
lDM: TMyDataModule;
begin
lDM := TMyDataModule.Create(nil);
try
lDM.qryCustomers.Open;
Result := TFDMemTable.Create(nil);
TFDMemTable(Result).CloneCursor(lDM.qryCustomers, True);
finally
lDM.Free;
end;
end;
procedure TRenderSampleController.GetCustomersAsDataSetWithRefLinks;
var
lDM: TMyDataModule;
@ -909,6 +936,14 @@ begin
Render(HTTP_STATUS.OK, ObjectDict().Add('data', People));
end;
function TRenderSampleController.GetPeople_AsObjectList_AsFunction: TEnumerable<TPerson>;
begin
Result := TObjectList<TPerson>.Create(True);
TObjectList<TPerson>(Result).Add(TPerson.GetNew('Daniele','Teti', EncodeDate(1979, 11, 4), True));
TObjectList<TPerson>(Result).Add(TPerson.GetNew('John','Doe', EncodeDate(1879, 10, 2), False));
TObjectList<TPerson>(Result).Add(TPerson.GetNew('Jane','Doe', EncodeDate(1883, 1, 5), True));
end;
procedure TRenderSampleController.GetPeople_AsObjectList_HATEOAS;
var
p: TPerson;

View File

@ -215,12 +215,12 @@
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="4">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
@ -627,6 +627,127 @@
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
@ -827,127 +948,6 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSLaunchScreen"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>

View File

@ -0,0 +1,102 @@
unit AppControllerU;
interface
uses
MVCFramework,
MVCFramework.Commons,
MVCFramework.Logger;
type
[MVCPath('/')]
TApp1MainController = class(TMVCController)
public
[MVCPath('/name')]
[MVCHTTPMethod([httpGET])]
procedure Index;
[MVCPath('/list')]
[MVCHTTPMethod([httpGET])]
procedure GetCustomSessionData;
[MVCPath('/login/($username)')]
[MVCHTTPMethod([httpGET])]
procedure DoLogin(username: String);
[MVCPath('/fruit/($nameOfFruit)')]
[MVCHTTPMethod([httpGET])]
procedure RegisterFruit(nameOfFruit: String);
[MVCPath('/logout')]
[MVCHTTPMethod([httpGET])]
procedure DoLogout;
end;
implementation
uses
System.SysUtils,
System.Classes;
{ TApp1MainController }
procedure TApp1MainController.DoLogin(username: String);
begin
Session['username'] := username;
ResponseStream
.AppendLine('Logged as ' + username)
.AppendLine
.AppendLine('in address of browser type: ')
.AppendLine('http://localhost:8080/list to check the current values in session ')
.AppendLine('http://localhost:8080/fruit/apple to register apple ')
.AppendLine('http://localhost:8080/fruit/banana to register banana ')
.AppendLine('http://localhost:8080/logout to end session ')
.AppendLine('http://localhost:8080/login/johndoe to login as johndoe');
RenderResponseStream;
end;
procedure TApp1MainController.RegisterFruit(nameOfFruit: String);
begin
Session[nameOfFruit] := nameOfFruit;
Redirect('/list');
end;
procedure TApp1MainController.DoLogout;
begin
Context.SessionStop(false);
Render('Logout');
end;
procedure TApp1MainController.GetCustomSessionData;
var
I: Integer;
lList: TArray<String>;
begin
lList := Session.Keys;
ResponseStream.AppendLine('List of fruits:');
for I := 0 to Length(lList) - 1 do
begin
ResponseStream.AppendLine(IntToStr(I + 1) + '-' + Session[lList[I]]);
end;
RenderResponseStream;
end;
procedure TApp1MainController.Index;
begin
ContentType := TMVCMediaType.TEXT_PLAIN;
// do not create session if not already created
if Context.SessionStarted then
begin
// automaticaly create the session
Render('Session[''username''] = ' + Session['username']);
end
else
begin
Render(400, 'Session not created. Do login first');
end;
end;
end.

View File

@ -0,0 +1,55 @@
program FileBasedSessionSample;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
MVCFramework,
MVCFramework.Signal,
{$IFDEF MSWINDOWS}
Winapi.Windows,
Winapi.ShellAPI,
{$ENDIF }
Web.WebReq,
Web.WebBroker,
IdHTTPWebBrokerBridge,
WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
AppControllerU in 'AppControllerU.pas';
{$R *.res}
procedure RunServer(APort: Integer);
var
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting HTTP Server or port %d', [APort]));
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try
LServer.DefaultPort := APort;
LServer.Active := True;
{$IFDEF MSWINDOWS}
//ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/login/john'), nil, nil, SW_SHOW);
{$ENDIF}
Writeln('CTRL+C to stop the server');
WaitForTerminationSignal;
EnterInShutdownState;
finally
LServer.Free;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
try
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := WebModuleClass;
WebRequestHandlerProc.MaxConnections := 1024;
RunServer(8080);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end
end.

View File

@ -1,28 +1,18 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{84344511-1DC2-41BA-8689-9F36C1D475BE}</ProjectGuid>
<MainSource>dmvcframeworkDT.dpk</MainSource>
<ProjectGuid>{F9CBCE21-869A-478F-992C-88FCAC97BC8B}</ProjectGuid>
<ProjectVersion>19.5</ProjectVersion>
<FrameworkType>None</FrameworkType>
<FrameworkType>VCL</FrameworkType>
<MainSource>FileBasedSessionSample.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Package</AppType>
<AppType>Console</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
<Base_Android>true</Base_Android>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
<Base_Android64>true</Base_Android64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
@ -49,13 +39,15 @@
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<SanitizedProjectName>FileBasedSessionSample</SanitizedProjectName>
<DCC_UnitSearchPath>..\..\sources;..\..\lib\delphistompclient;..\..\lib\loggerpro;..\..\lib\dmustache;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<Manifest_File>None</Manifest_File>
<VerInfo_Locale>1040</VerInfo_Locale>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
@ -63,37 +55,14 @@
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<GenDll>true</GenDll>
<GenPackage>true</GenPackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_CBuilderOutput>All</DCC_CBuilderOutput>
<SanitizedProjectName>dmvcframeworkDT</SanitizedProjectName>
<VerInfo_Locale>1040</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DCC_Description>DelphiMVCFramework IDE Expert</DCC_Description>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android64)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<EnabledSysJars>annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_UsePackage>rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;dmvcframeworkRT;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UnitSearchPath>..\..\sources;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_Description>DelphiMVCFramework 3.x - Design Time Support</DCC_Description>
<DllSuffix>110</DllSuffix>
<DCC_UsePackage>cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;JvDotNetCtrls;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;JvXPCtrls;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;FMXfrx17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;CloudService;dxPScxCommonRS17;FmxTeeUI;frxDB17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;JvRuntimeDesign;dxPScxVGridLnkRS17;JclDeveloperTools;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;MyFrameTestPackage;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;fs17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;DataBindingsVCL170;dxSkinOffice2010SilverRS17;vcldbx;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DataBindings;DBXOdbcDriver;IcsCommonDXE3Run;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;FMXTee;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;Jcl;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;Intraweb;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;fsDB17;inet;dorm_runtime_xe3;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;inetdbbde;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;MetropolisUILiveTile;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;vclribbon;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;CodeSiteExpressPkg;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;JvDocking;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;frx17;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;JclContainers;NxAddonsRun_dxe3;CPortLibDXE;JvSystem;dxorgcRS17;svnui;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;FMXfrxDB17;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;JclVcl;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;frxe17;svn;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;bdertl;VirtualTreesR;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_UsePackage>cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;dxPScxCommonRS17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;dxPScxVGridLnkRS17;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;dxSkinOffice2010SilverRS17;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DBXOdbcDriver;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;inet;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;NxAddonsRun_dxe3;JvSystem;dxorgcRS17;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
@ -104,12 +73,10 @@
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<DCC_MapFile>3</DCC_MapFile>
<DCC_ConsoleTarget>true</DCC_ConsoleTarget>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_UNSUPPORTED_CONSTRUCT>false</DCC_UNSUPPORTED_CONSTRUCT>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=Daniele Teti and the DMVCFramework Team;LegalTrademarks=DelphiMVCFramework;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DllSuffix>111</DllSuffix>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
@ -117,51 +84,15 @@
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="rtl.dcp"/>
<DCCReference Include="designide.dcp"/>
<DCCReference Include="ExpertsCreators.dcp"/>
<DCCReference Include="IndySystem.dcp"/>
<DCCReference Include="IndyProtocols.dcp"/>
<DCCReference Include="IndyCore.dcp"/>
<DCCReference Include="dbrtl.dcp"/>
<DCCReference Include="dmvcframeworkRT.dcp"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas">
<Form>frmDMVCNewProject</Form>
<DCCReference Include="WebModuleUnit1.pas">
<Form>WebModule1</Form>
<DesignClass>TWebModule</DesignClass>
</DCCReference>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas">
<Form>frmDMVCNewUnit</Form>
</DCCReference>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Expert.Registration.pas"/>
<DCCReference Include="..\..\ideexpert\DMVC.Splash.Registration.pas"/>
<RcItem Include="..\..\ideexpert\DMVC.Expert.NewProject.ico">
<ResourceType>ICON</ResourceType>
<ResourceId>DMVCNewProjectIcon</ResourceId>
</RcItem>
<RcItem Include="..\..\ideexpert\DMVC.Expert.NewUnit.ico">
<ResourceType>ICON</ResourceType>
<ResourceId>DMVCNewUnitIcon</ResourceId>
</RcItem>
<RcItem Include="..\..\ideexpert\SplashScreen.bmp">
<ResourceType>BITMAP</ResourceType>
<ResourceId>SplashScreen</ResourceId>
</RcItem>
<DCCReference Include="AppControllerU.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
@ -176,37 +107,60 @@
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Package</Borland.ProjectType>
<Borland.ProjectType/>
<BorlandProject>
<Delphi.Personality>
<VersionInfo>
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">1</VersionInfo>
<VersionInfo Name="MinorVer">0</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
<VersionInfo Name="PreRelease">False</VersionInfo>
<VersionInfo Name="Special">False</VersionInfo>
<VersionInfo Name="Private">False</VersionInfo>
<VersionInfo Name="DLL">False</VersionInfo>
<VersionInfo Name="Locale">1040</VersionInfo>
<VersionInfo Name="CodePage">1252</VersionInfo>
</VersionInfo>
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription"/>
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"/>
<VersionInfoKeys Name="LegalCopyright"/>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename"/>
<VersionInfoKeys Name="ProductName"/>
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
<VersionInfoKeys Name="CFBundleName"/>
<VersionInfoKeys Name="CFBundleDisplayName"/>
<VersionInfoKeys Name="CFBundleIdentifier"/>
<VersionInfoKeys Name="CFBundleVersion"/>
<VersionInfoKeys Name="CFBundlePackageType"/>
<VersionInfoKeys Name="CFBundleSignature"/>
<VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/>
<VersionInfoKeys Name="CFBundleExecutable"/>
</VersionInfoKeys>
<Source>
<Source Name="MainSource">dmvcframeworkDT.dpk</Source>
<Source Name="MainSource">FileBasedSessionSample.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k170.bpl">Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp170.bpl">Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="4">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<DeployFile LocalName="Win32\Debug\FileBasedSessionSample.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>FileBasedSessionSample.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule"/>
<DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\dmvcframeworkDT104.bpl" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="Win32\Debug\SessionSample.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
@ -933,9 +887,6 @@
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Android">False</Platform>
<Platform value="Android64">False</Platform>
<Platform value="Linux64">False</Platform>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>

View File

@ -0,0 +1,11 @@
object WebModule1: TWebModule1
OnCreate = WebModuleCreate
Actions = <
item
Default = True
Name = 'DefaultHandler'
PathInfo = '/'
end>
Height = 230
Width = 415
end

View File

@ -0,0 +1,44 @@
unit WebModuleUnit1;
interface
uses
System.SysUtils,
System.Classes,
Web.HTTPApp,
MVCFramework;
type
TWebModule1 = class(TWebModule)
procedure WebModuleCreate(Sender: TObject);
private
MVC: TMVCEngine;
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TWebModule1;
implementation
{$R *.dfm}
uses AppControllerU, MVCFramework.Commons;
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
MVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
Config[TMVCConfigKey.SessionTimeout] := '10'; // 10minutes
Config[TMVCConfigKey.DefaultContentType] := 'text/plain';
Config[TMVCConfigKey.SessionType] := 'file';
end);
MVC.AddController(TApp1MainController);
end;
end.

View File

@ -103,6 +103,18 @@ type
procedure EndUpdates;
end;
TSQLQueryWithName = record
Name: String;
SQLText: String;
BackEnd: String; //TMVCActiveRecordBackEnd
end;
TRQLQueryWithName = record
Name: String;
RQLText: String;
end;
TFieldsMap = class(TObjectDictionary<TRTTIField, TFieldInfo>)
private
fWritableFieldsCount: Integer;
@ -133,6 +145,22 @@ type
constructor Create(const PartitionClause: String);
end;
MVCNamedSQLQueryAttribute = class(MVCActiveRecordCustomAttribute)
public
Name: string;
SQLQuery: String;
Backend: String; //TMVCActiveRecordBackEnd
constructor Create(aName: string; aSQLSelect: String); overload;
constructor Create(aName: string; aSQLSelect: String; aBackEnd: String); overload;
end;
MVCNamedRQLQueryAttribute = class(MVCActiveRecordCustomAttribute)
public
Name: string;
RQLQuery: String;
constructor Create(aName: string; aRQL: String);
end;
MVCTableFieldAttribute = class(MVCActiveRecordCustomAttribute)
public
FieldName: string;
@ -202,6 +230,8 @@ type
fPrimaryKeyOptions: TMVCActiveRecordFieldOptions;
fPrimaryKeySequenceName: string;
fPrimaryKeyFieldType: TFieldType;
fNamedSQLQueries: TArray<TSQLQueryWithName>;
fNamedRQLQueries: TArray<TRQLQueryWithName>;
public
constructor Create;
destructor Destroy; override;
@ -226,7 +256,6 @@ type
fBackendDriver: string;
fTableMap: TMVCTableMap;
function GetPartitionInfo: TPartitionInfo;
function GetBackEnd: string;
function GetConnection: TFDConnection;
procedure InitTableInfo;
class function ExecQuery(
@ -256,7 +285,7 @@ type
const Unidirectional: Boolean;
const DirectExecute: Boolean): TDataSet; overload;
procedure FillPrimaryKey(const SequenceName: string);
function ExecNonQuery(const SQL: string; RefreshAutoGenerated: Boolean = false): int64;
function ExecNonQuery(const SQL: string; RefreshAutoGenerated: Boolean = false): Int64;
overload;
class function GetByPK(aActiveRecord: TMVCActiveRecord; const aValue: string; const aFieldType: TFieldType;
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; overload;
@ -330,10 +359,11 @@ type
function GenerateSelectSQL: string;
function SQLGenerator: TMVCSQLGenerator;
function InternalCount(const RQL: string): int64;
function InternalCount(const RQL: string): Int64;
function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer)
: TMVCActiveRecordList;
: TMVCActiveRecordList; overload;
function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer;
const OutList: TMVCActiveRecordList): UInt32; overload;
public
constructor Create(aLazyLoadConnection: Boolean); overload;
{ cannot be virtual! }
@ -342,6 +372,7 @@ type
procedure EnsureConnection;
procedure Assign(ActiveRecord: TMVCActiveRecord); virtual;
procedure InvalidateConnection(const ReacquireAfterInvalidate: Boolean = false);
function GetBackEnd: string;
/// <summary>
/// Executes an Insert (pk is null) or an Update (pk is not null)
/// </summary>
@ -354,7 +385,7 @@ type
const aRaiseException: Boolean = True): Boolean;
procedure Insert;
function GetMapping: TMVCFieldsMapping;
function LoadByPK(const id: int64): Boolean; overload; virtual;
function LoadByPK(const id: Int64): Boolean; overload; virtual;
function LoadByPK(const id: string): Boolean; overload; virtual;
function LoadByPK(const id: TGuid): Boolean; overload; virtual;
function LoadByPK(const id: string; const aFieldType: TFieldType): Boolean; overload; virtual;
@ -372,51 +403,25 @@ type
procedure AddChildren(const ChildObject: TObject);
procedure RemoveChildren(const ChildObject: TObject);
function GetPrimaryKeyFieldType: TFieldType;
// dynamic access
property Attributes[const AttrName: string]: TValue read GetAttributes write SetAttributes;
function FindSQLQueryByName(const QueryName: String; out NamedSQLQuery: TSQLQueryWithName): Boolean;
function FindRQLQueryByName(const QueryName: String; out NamedRQLQuery: TRQLQueryWithName): Boolean;
property Attributes[const AttrName: string]: TValue
read GetAttributes
write SetAttributes;
[MVCDoNotSerialize]
property TableName: string read GetTableName write SetTableName;
property TableName: string
read GetTableName
write SetTableName;
[MVCDoNotSerialize]
property PrimaryKeyIsAutogenerated: Boolean read GetPrimaryKeyIsAutogenerated
property PrimaryKeyIsAutogenerated: Boolean
read GetPrimaryKeyIsAutogenerated
write SetPrimaryKeyIsAutogenerated;
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetScalar(const SQL: string; const Params: array of Variant): Variant;
class function Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant)
: TMVCActiveRecordList; overload;
class function Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant;
const Connection: TFDConnection): TMVCActiveRecordList; overload;
class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string;
const MaxRecordCount: Integer)
: TMVCActiveRecordList; overload;
class function DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64;
function SelectRQL(const RQL: string; const MaxRecordCount: Integer)
: TMVCActiveRecordList; overload;
class function Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
const Params: array of Variant)
: TMVCActiveRecordList; overload;
class function Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
const Params: array of Variant;
const Connection: TFDConnection): TMVCActiveRecordList; overload;
class function All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
overload;
class function DeleteAll(const aClass: TMVCActiveRecordClass): int64; overload;
function Count(const RQL: string = ''): int64; overload;
class function Count(const aClass: TMVCActiveRecordClass; const RQL: string = '')
: int64; overload;
class function SelectDataSet(const SQL: string; const Params: array of Variant;
const Unidirectional: Boolean = False;
const DirectExecute: Boolean = False): TDataSet; overload;
class function SelectDataSet(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType;
const Unidirectional: Boolean = False;
const DirectExecute: Boolean = False): TDataSet; overload;
class function CurrentConnection: TFDConnection;
end;
@ -443,21 +448,55 @@ type
end;
TMVCActiveRecordHelper = class helper for TMVCActiveRecord
{ GetByPK }
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: Int64;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid;
const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload;
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: string; const aFieldType: TFieldType;
const RaiseExceptionIfNotFound: Boolean): T; overload;
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: int64;
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: Int64;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: string;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: TGuid;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
{ Select }
/// <summary>
/// Returns a TObjectList<TMVCActiveRecord> from a SQL using variant params
/// </summary>
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string;
const Params: array of Variant;
const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>; overload;
/// <summary>
/// Returns a TObjectList<TMVCActiveRecord> from a SQL using typed params
/// </summary>
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string;
const Params: array of Variant;
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = [])
: TObjectList<T>; overload;
/// <summary>
/// Fills a TObjectList<TMVCActiveRecord> from a SQL using typed params.
/// Returns number of the records in the list (not only the selected records, but the current .Count of the list)
/// </summary>
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions;
const OutList: TObjectList<T>): UInt32; overload;
class function Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant)
: TMVCActiveRecordList; overload;
class function Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant;
const Connection: TFDConnection): TMVCActiveRecordList; overload;
class function Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant;
const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; overload;
{ SelectOne }
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string;
const Params: array of Variant;
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = [];
@ -465,14 +504,30 @@ type
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string;
const Params: array of Variant;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
{ SelectRQL }
function SelectRQL(const RQL: string; const MaxRecordCount: Integer)
: TMVCActiveRecordList; overload;
class function SelectRQL<T: constructor, TMVCActiveRecord>(const RQL: string;
const MaxRecordCount: Integer)
: TObjectList<T>; overload;
class function SelectRQL<T: constructor, TMVCActiveRecord>(const RQL: string;
const MaxRecordCount: Integer; const OutList: TObjectList<T>): UInt32; overload;
class function SelectOneByRQL<T: constructor, TMVCActiveRecord>(const RQL: string;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string;
const MaxRecordCount: Integer)
: TMVCActiveRecordList; overload;
class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string;
const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; overload;
{ Misc }
class function All<T: TMVCActiveRecord, constructor>: TObjectList<T>; overload;
class function DeleteRQL<T: TMVCActiveRecord>(const RQL: string = ''): int64; overload;
class function Count<T: TMVCActiveRecord>(const RQL: string = ''): int64; overload;
class function DeleteRQL<T: TMVCActiveRecord>(const RQL: string = ''): Int64; overload;
class function Count<T: TMVCActiveRecord>(const RQL: string = ''): Int64; overload;
{ Where }
class function Where<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant)
: TObjectList<T>; overload;
@ -483,6 +538,28 @@ type
class function Where<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant;
const ParamTypes: array of TFieldType): TObjectList<T>; overload;
class function Where<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant;
const ParamTypes: array of TFieldType;
const OutList: TObjectList<T>): UInt32; overload;
class function Where(
const aClass: TMVCActiveRecordClass;
const SQLWhere: string;
const Params: array of Variant)
: TMVCActiveRecordList; overload;
class function Where(
const aClass: TMVCActiveRecordClass;
const SQLWhere: string;
const Params: array of Variant;
const Connection: TFDConnection): TMVCActiveRecordList; overload;
class function Where(
const aClass: TMVCActiveRecordClass;
const SQLWhere: string;
const Params: array of Variant;
const Connection: TFDConnection;
const OutList: TMVCActiveRecordList): UInt32; overload;
{ GetXXXByWhere }
class function GetOneByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload;
class function GetOneByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
@ -493,8 +570,45 @@ type
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
const Params: array of Variant; const ParamTypes: array of TFieldType;
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
{ Merge }
class function Merge<T: TMVCActiveRecord>(CurrentList,
NewList: TObjectList<T>; const MergeMode: TMergeMode = [mmInsert, mmUpdate, mmDelete]): IMVCMultiExecutor<T>;
{ Misc }
class function All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
overload;
class function DeleteAll(const aClass: TMVCActiveRecordClass): Int64; overload;
class function DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): Int64; overload;
function Count(const RQL: string = ''): Int64; overload;
class function Count(const aClass: TMVCActiveRecordClass; const RQL: string = '')
: int64; overload;
{ SelectDataSet }
class function SelectDataSet(const SQL: string; const Params: array of Variant;
const Unidirectional: Boolean = False;
const DirectExecute: Boolean = False): TDataSet; overload;
class function SelectDataSet(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType;
const Unidirectional: Boolean = False;
const DirectExecute: Boolean = False): TDataSet; overload;
{ NamedQuery}
class function SelectByNamedQuery<T: TMVCActiveRecord, constructor>(
const QueryName: String;
const Params: array of Variant;
const ParamTypes: array of TFieldType;
const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>;
class function SelectRQLByNamedQuery<T: constructor, TMVCActiveRecord>(
const QueryName: String;
const Params: array of const;
const MaxRecordCount: Integer): TObjectList<T>;
class function DeleteRQLByNamedQuery<T: TMVCActiveRecord, constructor>(
const QueryName: String;
const Params: array of const): Int64;
class function CountRQLByNamedQuery<T: TMVCActiveRecord, constructor>(
const QueryName: string;
const Params: array of const): Int64;
end;
IMVCEntitiesRegistry = interface
@ -1234,6 +1348,43 @@ begin
end;
end;
function TMVCActiveRecord.FindRQLQueryByName(const QueryName: String;
out NamedRQLQuery: TRQLQueryWithName): Boolean;
var
I: Integer;
begin
for I := Low(fTableMap.fNamedRQLQueries) to High(fTableMap.fNamedRQLQueries) do
begin
if SameText(QueryName, fTableMap.fNamedRQLQueries[I].Name) then
begin
NamedRQLQuery := fTableMap.fNamedRQLQueries[I];
Exit(True);
end;
end;
Result := False;
end;
function TMVCActiveRecord.FindSQLQueryByName(const QueryName: String;
out NamedSQLQuery: TSQLQueryWithName): Boolean;
var
I: Integer;
lBackEnd: String;
begin
for I := Low(fTableMap.fNamedSQLQueries) to High(fTableMap.fNamedSQLQueries) do
begin
if SameText(QueryName, fTableMap.fNamedSQLQueries[I].Name) then
begin
lBackEnd := fTableMap.fNamedSQLQueries[I].BackEnd;
if lBackEnd.IsEmpty or (lBackEnd = GetBackEnd) then
begin
NamedSQLQuery := fTableMap.fNamedSQLQueries[I];
Exit(True);
end;
end;
end;
Result := False;
end;
class function TMVCActiveRecord.ExecQuery(const SQL: string; const Values: array of Variant;
const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet;
begin
@ -1248,6 +1399,8 @@ var
lPrimaryFieldTypeAsStr: string;
lTableMap: TMVCTableMap;
lPKCount: Integer;
lNamedSQLQueryCount: Integer;
lNamedRQLQueryCount: Integer;
begin
if ActiveRecordTableMapRegistry.TryGetValue(Self, fTableMap) then
begin
@ -1269,6 +1422,8 @@ begin
lTableMap.fRTTIType := gCtx.GetType(Self.ClassInfo) as TRttiInstanceType;
lTableMap.fObjAttributes := lTableMap.fRTTIType.GetAttributes;
lPKCount := 0;
lNamedSQLQueryCount := Length(lTableMap.fNamedSQLQueries);
lNamedRQLQueryCount := Length(lTableMap.fNamedRQLQueries);
for lAttribute in lTableMap.fObjAttributes do
begin
if lAttribute is MVCTableAttribute then
@ -1287,13 +1442,30 @@ begin
lTableMap.fPartitionClause := MVCPartitionAttribute(lAttribute).PartitionClause;
Continue;
end;
if lAttribute is MVCNamedSQLQueryAttribute then
begin
Inc(lNamedSQLQueryCount);
SetLength(lTableMap.fNamedSQLQueries, lNamedSQLQueryCount);
lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].Name := MVCNamedSQLQueryAttribute(lAttribute).Name;
lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].SQLText := MVCNamedSQLQueryAttribute(lAttribute).SQLQuery;
lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].BackEnd := MVCNamedSQLQueryAttribute(lAttribute).Backend;
Continue;
end;
if lAttribute is MVCNamedRQLQueryAttribute then
begin
Inc(lNamedRQLQueryCount);
SetLength(lTableMap.fNamedRQLQueries, lNamedRQLQueryCount);
lTableMap.fNamedRQLQueries[lNamedRQLQueryCount - 1].Name := MVCNamedRQLQueryAttribute(lAttribute).Name;
lTableMap.fNamedRQLQueries[lNamedRQLQueryCount - 1].RQLText := MVCNamedRQLQueryAttribute(lAttribute).RQLQuery;
Continue;
end;
end;
if lTableMap.fTableName = '' then
begin
if [eaCreate, eaUpdate, eaDelete] * lTableMap.fEntityAllowedActions <> [] then
begin
raise Exception.Create('Cannot find TableNameAttribute');
raise Exception.Create('Cannot find TableNameAttribute on class ' + ClassName + ' - [HINT] Is this class decorated with MVCTable and its fields with MVCTableField?');
end;
end;
@ -1353,7 +1525,7 @@ begin
lTableMap.fMap.EndUpdates;
if (lPKCount + lTableMap.fMap.WritableFieldsCount + lTableMap.fMap.ReadableFieldsCount) = 0 then
raise EMVCActiveRecord.Create(
'No fields nor PKs defined. [HINT] Use MVCTableField in private fields');
'No fields nor PKs defined in class ' + ClassName + '. [HINT] Use MVCTableField in private fields');
lTableMap.fPartitionInfoInternal := nil;
ActiveRecordTableMapRegistry.AddTableMap(Self, lTableMap);
@ -1419,6 +1591,16 @@ begin
Result := GetScalar(lSQL, []);
end;
function TMVCActiveRecord.InternalSelectRQL(const RQL: string;
const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32;
var
lSQL: string;
begin
lSQL := SQLGenerator.CreateSQLWhereByRQL(RQL, GetMapping, True, false, MaxRecordCount);
LogD(Format('RQL [%s] => SQL [%s]', [RQL, lSQL]));
Result := Where(TMVCActiveRecordClass(Self.ClassType), lSQL, [], nil, OutList);
end;
function TMVCActiveRecord.InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList;
var
lSQL: string;
@ -1494,19 +1676,19 @@ begin
end;
end;
class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string;
class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string;
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord;
begin
Result := GetByPK(aClass.Create, aValue, ftString, RaiseExceptionIfNotFound);
end;
class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64;
class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64;
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord;
begin
Result := GetByPK(aClass.Create, aValue.ToString, ftInteger, RaiseExceptionIfNotFound);
end;
class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid;
class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid;
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord;
begin
Result := GetByPK(aClass.Create, aValue.ToString, ftGuid, RaiseExceptionIfNotFound);
@ -1657,6 +1839,72 @@ begin
end;
end;
class function TMVCActiveRecordHelper.SelectRQL<T>(const RQL: string;
const MaxRecordCount: Integer; const OutList: TObjectList<T>): UInt32;
var
lAR: TMVCActiveRecord;
lSQL: string;
begin
lAR := T.Create;
try
lSQL := lAR.SQLGenerator.CreateSQLWhereByRQL(RQL, lAR.GetMapping, MaxRecordCount > -1, false, MaxRecordCount).Trim;
lSQL := TMVCSQLGenerator.RemoveInitialWhereKeyword(lSQL);
Result := Where<T>(lSQL, [], [], OutList);
finally
lAR.Free;
end;
end;
class function TMVCActiveRecordHelper.SelectRQLByNamedQuery<T>(
const QueryName: string;
const Params: array of const;
const MaxRecordCount: Integer): TObjectList<T>;
var
lT: T;
lRQLQuery: TRQLQueryWithName;
begin
lT := T.Create;
try
if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then
begin
raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]);
end;
Result := SelectRQL<T>(Format(lRQLQuery.RQLText, Params), MaxRecordCount);
finally
lT.Free;
end;
end;
class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string;
const Params: array of Variant; const ParamTypes: array of TFieldType;
const OutList: TObjectList<T>): UInt32;
var
lAR: TMVCActiveRecord;
lFilter: string;
begin
lAR := T.Create;
try
lFilter := lAR.SQLGenerator.GetDefaultSQLFilter(True);
if SQLWhere.Trim.IsEmpty() or SQLWhere.Trim.StartsWith('/*limit*/') or SQLWhere.Trim.StartsWith('/*sort*/') then
begin
Result := Select<T>(lAR.GenerateSelectSQL + lFilter + SQLWhere, Params, ParamTypes, [], OutList);
end
else
begin
if lFilter.IsEmpty then
begin
Result := Select<T>(lAR.GenerateSelectSQL + ' WHERE ' + SQLWhere, Params, ParamTypes, [], OutList);
end
else
begin
Result := Select<T>(lAR.GenerateSelectSQL + lFilter + ' AND ' + SQLWhere, Params, ParamTypes, [], OutList);
end;
end;
finally
lAR.Free;
end;
end;
function TMVCActiveRecord.GetPartitionInfo: TPartitionInfo;
var
lRQLCompilerClass: TRQLCompilerClass;
@ -1733,7 +1981,7 @@ begin
[GetEnumName(TypeInfo(TMVCEntityAction), Ord(aEntityAction)), ClassName]) at ReturnAddress;
end;
class function TMVCActiveRecord.Count(const aClass: TMVCActiveRecordClass; const RQL: string): int64;
class function TMVCActiveRecordHelper.Count(const aClass: TMVCActiveRecordClass; const RQL: string): int64;
var
lAR: TMVCActiveRecord;
begin
@ -1747,7 +1995,7 @@ begin
end;
end;
function TMVCActiveRecord.Count(const RQL: string = ''): int64;
function TMVCActiveRecordHelper.Count(const RQL: string = ''): int64;
begin
Result := InternalCount(RQL);
end;
@ -1757,11 +2005,49 @@ begin
Result := TMVCActiveRecord.Count(TMVCActiveRecordClass(T), RQL);
end;
class function TMVCActiveRecordHelper.CountRQLByNamedQuery<T>(
const QueryName: string;
const Params: array of const): Int64;
var
lRQLQuery: TRQLQueryWithName;
lT: T;
begin
lT := T.Create;
try
if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then
begin
raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]);
end;
Result := Count<T>(Format(lRQLQuery.RQLText, Params));
finally
lT.Free;
end;
end;
class function TMVCActiveRecordHelper.DeleteRQL<T>(const RQL: string): int64;
begin
Result := TMVCActiveRecord.DeleteRQL(TMVCActiveRecordClass(T), RQL);
end;
class function TMVCActiveRecordHelper.DeleteRQLByNamedQuery<T>(
const QueryName: String;
const Params: array of const): Int64;
var
lRQLQuery: TRQLQueryWithName;
lT: T;
begin
lT := T.Create;
try
if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then
begin
raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]);
end;
Result := DeleteRQL<T>(Format(lRQLQuery.RQLText, Params));
finally
lT.Free;
end;
end;
class function TMVCActiveRecord.CurrentConnection: TFDConnection;
begin
Result := ActiveRecordConnectionsRegistry.GetCurrent;
@ -1802,7 +2088,7 @@ begin
OnAfterDelete;
end;
class function TMVCActiveRecord.DeleteAll(const aClass: TMVCActiveRecordClass): int64;
class function TMVCActiveRecordHelper.DeleteAll(const aClass: TMVCActiveRecordClass): int64;
var
lAR: TMVCActiveRecord;
begin
@ -1815,7 +2101,7 @@ begin
end;
end;
class function TMVCActiveRecord.DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64;
class function TMVCActiveRecordHelper.DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64;
var
lAR: TMVCActiveRecord;
begin
@ -2446,40 +2732,25 @@ begin
end;
end;
class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; const SQL: string;
class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant): TMVCActiveRecordList;
begin
Result := Select(aClass, SQL, Params, nil);
end;
class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; const SQL: string;
class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass; const SQL: string;
const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList;
var
lDataSet: TDataSet;
lAR: TMVCActiveRecord;
begin
Result := TMVCActiveRecordList.Create;
try
lDataSet := ExecQuery(SQL, Params, Connection, True, False);
try
while not lDataSet.Eof do
begin
lAR := aClass.Create;
Result.Add(lAR);
lAR.LoadByDataset(lDataSet);
lDataSet.Next;
end;
finally
lDataSet.Free;
end;
Select(aClass, SQL, Params, Connection, Result);
except
Result.Free;
raise;
end;
end;
class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant;
class function TMVCActiveRecordHelper.SelectDataSet(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType; const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet;
begin
Result := TMVCActiveRecord.ExecQuery(SQL, Params, ParamTypes, Unidirectional, DirectExecute);
@ -2491,17 +2762,72 @@ begin
Result := Select<T>(SQL, Params, [], Options);
end;
class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant;
class function TMVCActiveRecordHelper.SelectDataSet(const SQL: string; const Params: array of Variant;
const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet;
begin
Result := TMVCActiveRecord.ExecQuery(SQL, Params, Unidirectional, DirectExecute);
end;
function TMVCActiveRecord.SelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList;
function TMVCActiveRecordHelper.SelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList;
begin
Result := InternalSelectRQL(RQL, MaxRecordCount);
end;
class function TMVCActiveRecordHelper.SelectRQL(const aClass: TMVCActiveRecordClass;
const RQL: string; const MaxRecordCount: Integer;
const OutList: TMVCActiveRecordList): UInt32;
var
lAR: TMVCActiveRecord;
begin
lAR := aClass.Create(True);
try
Result := lAR.InternalSelectRQL(RQL, MaxRecordCount, OutList);
finally
lAR.Free;
end;
end;
class function TMVCActiveRecordHelper.Select<T>(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions; const OutList: TObjectList<T>): UInt32;
var
lDataSet: TDataSet;
lAR: TMVCActiveRecord;
begin
lDataSet := ExecQuery(SQL, Params, ParamTypes, True, False);
try
while not lDataSet.Eof do
begin
lAR := T.Create;
OutList.Add(lAR);
lAR.LoadByDataset(lDataSet, Options);
lDataSet.Next;
end;
Result := OutList.Count;
finally
lDataSet.Free;
end;
end;
class function TMVCActiveRecordHelper.SelectByNamedQuery<T>(
const QueryName: String; const Params: array of Variant;
const ParamTypes: array of TFieldType;
const Options: TMVCActiveRecordLoadOptions): TObjectList<T>;
var
lT: T;
lSQLQuery: TSQLQueryWithName;
begin
lT := T.Create;
try
if not lT.FindSQLQueryByName(QueryName, lSQLQuery) then
begin
raise EMVCActiveRecord.CreateFmt('NamedSQLQuery not found: %s', [QueryName]);
end;
Result := Select<T>(lSQLQuery.SQLText, Params, ParamTypes, Options);
finally
lT.Free;
end;
end;
class function TMVCActiveRecordHelper.Select<T>(const SQL: string; const Params: array of Variant;
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions): TObjectList<T>;
var
@ -2511,18 +2837,7 @@ var
begin
Result := TObjectList<T>.Create(True);
try
lDataSet := ExecQuery(SQL, Params, ParamTypes, True, False);
try
while not lDataSet.Eof do
begin
lAR := T.Create;
Result.Add(lAR);
lAR.LoadByDataset(lDataSet, Options);
lDataSet.Next;
end;
finally
lDataSet.Free;
end;
Select<T>(SQL, Params, ParamTypes, Options, Result);
except
Result.Free;
raise;
@ -2581,32 +2896,17 @@ end;
class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string; const Params: array of Variant;
const ParamTypes: array of TFieldType): TObjectList<T>;
var
lAR: TMVCActiveRecord;
lFilter: string;
begin
lAR := T.Create;
Result := TObjectList<T>.Create(True);
try
lFilter := lAR.SQLGenerator.GetDefaultSQLFilter(True);
if SQLWhere.Trim.IsEmpty() or SQLWhere.Trim.StartsWith('/*limit*/') or SQLWhere.Trim.StartsWith('/*sort*/') then
begin
Result := Select<T>(lAR.GenerateSelectSQL + lFilter + SQLWhere, Params, ParamTypes)
end
else
begin
if lFilter.IsEmpty then
Result := Select<T>(lAR.GenerateSelectSQL + ' WHERE ' + SQLWhere, Params, ParamTypes)
else
begin
Result := Select<T>(lAR.GenerateSelectSQL + lFilter + ' AND ' + SQLWhere, Params, ParamTypes);
end;
end;
finally
lAR.Free;
Where<T>(SQLWhere, Params, ParamTypes, Result);
except
Result.Free;
raise;
end;
end;
class function TMVCActiveRecord.SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string;
class function TMVCActiveRecordHelper.SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string;
const MaxRecordCount: Integer): TMVCActiveRecordList;
var
lAR: TMVCActiveRecord;
@ -3000,6 +3300,20 @@ begin
OnAfterInsertOrUpdate;
end;
class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass;
const SQLWhere: string; const Params: array of Variant;
const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32;
var
lAR: TMVCActiveRecord;
begin
lAR := aClass.Create;
try
Result := Select(aClass, lAR.GenerateSelectSQL + SQLWhere, Params, Connection, OutList);
finally
lAR.Free;
end;
end;
procedure TMVCActiveRecord.AddChildren(const ChildObject: TObject);
begin
if fChildren = nil then
@ -3012,7 +3326,7 @@ begin
end;
end;
class function TMVCActiveRecord.All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
class function TMVCActiveRecordHelper.All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
var
lAR: TMVCActiveRecord;
begin
@ -3043,22 +3357,21 @@ begin
end;
end;
class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
const Params: array of Variant): TMVCActiveRecordList;
begin
Result := Where(aClass, SQLWhere, Params, nil);
end;
class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList;
var
lAR: TMVCActiveRecord;
begin
lAR := aClass.Create;
Result := TMVCActiveRecordList.Create;
try
Result := Select(aClass, lAR.GenerateSelectSQL + SQLWhere, Params, Connection);
finally
lAR.Free;
Where(aClass, SQLWhere, Params, Connection, Result);
except
Result.Free;
raise;
end;
end;
@ -4063,6 +4376,53 @@ begin
inherited;
end;
class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass;
const SQL: string; const Params: array of Variant;
const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32;
var
lDataSet: TDataSet;
lAR: TMVCActiveRecord;
begin
lDataSet := ExecQuery(SQL, Params, Connection, True, False);
try
while not lDataSet.Eof do
begin
lAR := aClass.Create;
OutList.Add(lAR);
lAR.LoadByDataset(lDataSet);
lDataSet.Next;
end;
Result := OutList.Count;
finally
lDataSet.Free;
end;
end;
{ MVCNamedSQLQueryAttribute }
constructor MVCNamedSQLQueryAttribute.Create(aName, aSQLSelect: String);
begin
Create(aName, aSQLSelect, '');
end;
constructor MVCNamedSQLQueryAttribute.Create(aName, aSQLSelect,
aBackEnd: String);
begin
inherited Create;
Name := aName;
SQLQuery := aSQLSelect;
BackEnd := aBackEnd;
end;
{ MVCNamedRQLQueryAttribute }
constructor MVCNamedRQLQueryAttribute.Create(aName, aRQL: String);
begin
inherited Create;
Name := aName;
RQLQuery := aRQL;
end;
initialization
gConnectionsLock := TObject.Create;

View File

@ -204,7 +204,7 @@ begin
begin
fEnvPath := TPath.Combine(fEnvPath, DotEnvDirectory);
end;
DoLog('Path = ' + DotEnvDirectory);
DoLog('Path = ' + fEnvPath);
fEnvDict.Clear;
lAllProfiles := ['default'] + fProfiles.ToArray();
DoLog('Active profile/s priority = [' + String.Join(',', lAllProfiles) + ']');

View File

@ -29,7 +29,8 @@ unit MVCFramework.FireDAC.Utils;
interface
uses
FireDAC.Comp.Client, FireDAC.Stan.Param, System.Rtti, JsonDataObjects;
FireDAC.Comp.Client, FireDAC.Stan.Param, System.Rtti, JsonDataObjects,
Data.DB, FireDAC.Comp.DataSet;
type
TFireDACUtils = class sealed
@ -51,13 +52,13 @@ type
TFDCustomMemTableHelper = class helper for TFDCustomMemTable
public
procedure InitFromMetadata(const AJSONMetadata: TJSONObject);
class function CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable; static;
end;
implementation
uses
System.Generics.Collections,
Data.DB,
System.Classes,
MVCFramework.Serializer.Commons,
System.SysUtils;
@ -222,6 +223,12 @@ begin
end;
end;
class function TFDCustomMemTableHelper.CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable;
begin
Result := TFDMemTable.Create(nil);
TFDMemTable(Result).CloneCursor(FDDataSet);
end;
procedure TFDCustomMemTableHelper.InitFromMetadata(const AJSONMetadata: TJSONObject);
begin
TFireDACUtils.CreateDatasetFromMetadata(Self, AJSONMetadata);

View File

@ -516,7 +516,7 @@ begin
FSecretKey := SecretKey;
FRegisteredClaims := TJWTRegisteredClaims.Create;
FCustomClaims := TJWTCustomClaims.Create;
FHMACAlgorithm := HMAC_HS512;
FHMACAlgorithm := HMACAlgorithm;
FLeewaySeconds := ALeewaySeconds;
FRegClaimsToChecks := [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore, TJWTCheckableClaim.IssuedAt];
end;

View File

@ -194,14 +194,6 @@ begin
LogE(E.ClassName + ': ' + AMessage);
end;
// procedure LogException(
// const AException: Exception;
// const AMessage: string);
// begin
// Log.Error(Format('[%s] %s (Custom message: "%s")', [AException.ClassName,
// AException.Message, AMessage]), LOGGERPRO_TAG);
// end;
procedure LogEnterMethod(const AMethodName: string);
begin
LogI('>> ' + AMethodName);
@ -266,27 +258,27 @@ end;
procedure SetDefaultLogger(const aLogWriter: ILogWriter);
begin
if gDefaultLogger = nil then
begin
TMonitor.Enter(gLock); // double check here
try
if gDefaultLogger = nil then
if gDefaultLogger = nil then
begin
TMonitor.Enter(gLock); // double check here
try
if gDefaultLogger = nil then
begin
if aLogWriter <> nil then
begin
if aLogWriter <> nil then
begin
gDefaultLogger := aLogWriter;
Log.Info('Custom Logger initialized', LOGGERPRO_TAG);
end
else
begin
InitializeDefaultLogger;
Log.Info('Default Logger initialized', LOGGERPRO_TAG);
end;
gDefaultLogger := aLogWriter;
Log.Info('Custom Logger initialized', LOGGERPRO_TAG);
end
else
begin
InitializeDefaultLogger;
Log.Info('Default Logger initialized', LOGGERPRO_TAG);
end;
finally
TMonitor.Exit(gLock);
end;
finally
TMonitor.Exit(gLock);
end;
end;
end;
procedure InitializeDefaultLogger;

View File

@ -179,6 +179,9 @@ var
begin
lDecompressed := TMemoryStream.Create;
try
{$IF defined(MACOS) or defined(IOS)}
lDecompressed.CopyFrom(aContentStream, 0); // MACOS automatically decompresses response body
{$ELSE}
if SameText(aContentEncoding, 'gzip') or SameText(aContentEncoding, 'deflate') then
begin
/// Certain types of deflate compression cannot be decompressed by the standard Zlib,
@ -202,6 +205,7 @@ begin
begin
raise EMVCRESTClientException.CreateFmt('Content-Encoding not supported [%s]', [aContentEncoding]);
end;
{$ENDIF}
SetLength(Result, lDecompressed.Size);
lDecompressed.Position := 0;

View File

@ -250,7 +250,7 @@ begin
begin
if LMethod.Visibility <> mvPublic then // 2020-08-08
Continue;
if (LMethod.MethodKind <> mkProcedure) { or LMethod.IsClassMethod } then
if not (LMethod.MethodKind in [mkProcedure, mkFunction]) then
Continue;
LAttributes := LMethod.GetAttributes;

View File

@ -1141,7 +1141,7 @@ begin
begin
// sqlite doesn't support boolean, so are identified as integers
// so we need to do some more checks...
if (aRTTIField.FieldType.TypeKind = tkEnumeration) and (aRTTIField.Name.ToLower.Contains('bool')) then
if (aRTTIField.FieldType.TypeKind = tkEnumeration) and (aRTTIField.FieldType.Handle = TypeInfo(Boolean)) then
begin
aRTTIField.SetValue(AObject, AField.AsInteger = 1);
end

View File

@ -77,7 +77,6 @@ type
const ASerializationAction: TMVCSerializationAction = nil
): string; overload;
function SerializeCollection(
const AList: TObject;
const AType: TMVCSerializationType = stDefault;
@ -151,6 +150,12 @@ type
const AIgnoredFields: TMVCIgnoredList = [];
const ANameCase: TMVCNameCase = ncAsIs
);
function SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue;
const AType: TMVCSerializationType = stDefault;
const AIgnoredAttributes: TMVCIgnoredList = nil;
const ASerializationAction: TMVCSerializationAction = nil): string;
end;
implementation
@ -274,6 +279,14 @@ begin
RaiseNotImplemented;
end;
function TMVCHTMLSerializer.SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue; const AType: TMVCSerializationType;
const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction): string;
begin
RaiseNotImplemented;
end;
function TMVCHTMLSerializer.SerializeCollection(const AList: IInterface;
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction): string;

View File

@ -94,6 +94,13 @@ type
const ASerializationAction: TMVCSerializationAction = nil
): string; overload;
function SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue;
const AType: TMVCSerializationType = stDefault;
const AIgnoredAttributes: TMVCIgnoredList = nil;
const ASerializationAction: TMVCSerializationAction = nil
): string; overload;
function SerializeCollection(
const AList: TObject;
const AType: TMVCSerializationType = stDefault;

View File

@ -72,6 +72,11 @@ type
end;
TMVCObjectDictionarySerializer = class(TInterfacedObject, IMVCTypeSerializer)
private
procedure InternalSerializeIMVCObjectDictionary(
lObjDict: TMVCObjectDictionary;
var lOutObject: TJsonObject;
const ASerializationAction: TMVCSerializationAction);
protected
fCurrentSerializer: TMVCJsonDataObjectsSerializer;
public
@ -469,27 +474,28 @@ procedure TMVCObjectDictionarySerializer.SerializeAttribute(
const AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
begin
raise EMVCDeserializationException.Create('Serialization as attribute not supported for this type');
end;
procedure TMVCObjectDictionarySerializer.SerializeRoot(const AObject: TObject;
out ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>;
const ASerializationAction: TMVCSerializationAction);
var
lObjDict: TMVCObjectDictionary;
lOutObject, lOutCustom: TJsonObject;
lOutObject: TJsonObject;
begin
lObjDict := TMVCObjectDictionary(AElementValue.AsInterface);
lOutObject := TJsonObject(ASerializerObject);
InternalSerializeIMVCObjectDictionary(lObjDict, lOutObject, nil);
end;
procedure TMVCObjectDictionarySerializer.InternalSerializeIMVCObjectDictionary(
lObjDict: TMVCObjectDictionary;
var lOutObject: TJsonObject;
const ASerializationAction: TMVCSerializationAction);
var
lOutCustom: TJsonObject;
lName: string;
lObj: TMVCObjectDictionary.TMVCObjectDictionaryValueItem;
lList: IMVCList;
lLinks: IMVCLinks;
lJSONType: TJsonDataType;
lJSONValue: TJsonBaseObject;
begin
lObjDict := TMVCObjectDictionary(AObject);
lOutObject := TJsonObject.Create;
try
for lName in lObjDict.Keys do
begin
lObj := lObjDict.Items[lName];
@ -585,10 +591,22 @@ begin
RaiseSerializationError('Invalid JSON');
end;
end;
// fCurrentSerializer.InternalObjectToJsonObject(lObj.Data, lOutObject.O[lName],
// TMVCSerializationType.stDefault, [], lObj.SerializationAction, lLinks, nil);
end;
end
end;
procedure TMVCObjectDictionarySerializer.SerializeRoot(const AObject: TObject;
out ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>;
const ASerializationAction: TMVCSerializationAction);
var
lObjDict: TMVCObjectDictionary;
lOutObject: TJsonObject;
begin
lObjDict := TMVCObjectDictionary(AObject);
lOutObject := TJsonObject.Create;
try
InternalSerializeIMVCObjectDictionary(lObjDict, lOutObject, ASerializationAction);
except
lOutObject.Free;
raise;

View File

@ -174,6 +174,13 @@ type
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = nil;
const ASerializationAction: TMVCSerializationAction = nil): string; overload;
function SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue;
const AType: TMVCSerializationType = stDefault;
const AIgnoredAttributes: TMVCIgnoredList = nil;
const ASerializationAction: TMVCSerializationAction = nil
): string; overload;
procedure RecordToJsonObject(const ARecord: Pointer; const ARecordTypeInfo: PTypeInfo;
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
@ -3027,7 +3034,14 @@ begin
begin
if Obj <> nil then
begin
ObjectToJsonObject(Obj, JSONArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes)
if Obj is TDataSet then
begin
DataSetToJsonArray(TDataSet(Obj), JSONArray.AddArray, TMVCNameCase.ncLowerCase, nil,nil,);
end
else
begin
ObjectToJsonObject(Obj, JSONArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes)
end;
end
else
begin
@ -3042,6 +3056,55 @@ begin
end;
end;
function TMVCJsonDataObjectsSerializer.SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue; const AType: TMVCSerializationType;
const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction): string;
var
I: Integer;
lCurrentArrayItem: TValue;
lJSONArr: TJsonArray;
lJObj: TJsonObject;
begin
if not ATValueContainingAnArray.IsArray then
begin
raise EMVCSerializationException.Create(String(ATValueContainingAnArray.TypeInfo^.Name) + ' is not an array');
end;
if ATValueContainingAnArray.GetArrayLength = 0 then
begin
Result := '[]';
end;
lJSONArr := TJsonArray.Create;
try
for I := 0 to ATValueContainingAnArray.GetArrayLength - 1 do
begin
lJObj := lJSONArr.AddObject;
lCurrentArrayItem := ATValueContainingAnArray.GetArrayElement(I);
if lCurrentArrayItem.IsObjectInstance then
begin
raise EMVCSerializationException.CreateFmt('Found a "%s" while serializing array. Instance types not allowed in arrays - [HINT] Use list of objects instead of array', [lCurrentArrayItem.AsObject.ClassName]);
end
else
begin
InternalRecordToJsonObject(
lCurrentArrayItem.GetReferenceToRawData,
lCurrentArrayItem.TypeInfo,
lJObj,
TMVCSerializationType.stFields,
nil,
nil,
nil,
nil
);
end;
end;
Result := lJSONArr.ToJSON();
finally
lJSONArr.free;
end;
end;
function TMVCJsonDataObjectsSerializer.SerializeCollection(const AList: IInterface; const AType: TMVCSerializationType;
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string;
begin
@ -3731,7 +3794,6 @@ begin
raise;
end;
end;
// lSer.JsonArrayToList(AJsonArray, AList, AClazz, AType, AIgnoredAttributes);
finally
lSer.Free;
end;

View File

@ -32,15 +32,18 @@ uses
System.SyncObjs,
System.SysUtils,
System.DateUtils,
System.Generics.Collections;
System.Generics.Collections, MVCFramework.Commons;
const
DEFAULT_SESSION_INACTIVITY = 60; // in minutes
type
EMVCSession = class(EMVCException)
TWebSession = class abstract
end;
TMVCWebSession = class abstract
private
FSessionId: string;
FLastAccess: TDateTime;
@ -48,22 +51,25 @@ type
protected
function GetItems(const AKey: string): string; virtual; abstract;
procedure SetItems(const AKey, AValue: string); virtual; abstract;
procedure SetLastAccess(Value: TDateTime);
public
constructor Create(const ASessionId: string; const ATimeout: UInt64); virtual;
destructor Destroy; override;
procedure MarkAsUsed; virtual;
function ToString: string; override;
function IsExpired: Boolean; virtual;
function Keys: TArray<String>; virtual; abstract;
class function TryFindSessionID(const ASessionID: String): Boolean; virtual;
class procedure TryDeleteSessionID(const ASessionID: String); virtual;
property Items[const AKey: string]: string read GetItems write SetItems; default;
property SessionId: string read FSessionId;
property LastAccess: TDateTime read FLastAccess;
property Timeout: UInt64 read FTimeout;
end;
TWebSessionClass = class of TWebSession;
TMVCWebSessionClass = class of TMVCWebSession;
TWebSessionMemory = class(TWebSession)
TMVCWebSessionMemory = class(TMVCWebSession)
private
FData: TDictionary<string, string>;
protected
@ -72,37 +78,61 @@ type
public
constructor Create(const ASessionId: string; const ATimeout: UInt64); override;
destructor Destroy; override;
function ToString: string; override;
property Data: TDictionary<string, string> read FData;
end;
TMVCWebSessionFile = class(TMVCWebSessionMemory)
private
fSessionFolder: String;
protected
procedure StartLoading;
procedure EndLoading;
function GetFileName: String; overload;
class function GetFileName(const SessionFolder, SessionID: String): String; overload;
procedure LoadFromFile;
procedure SaveToFile;
procedure OnValueNotify(Sender: TObject; const Item: String; Action: TCollectionNotification);
public
constructor Create(const SessionID: string; const Timeout: UInt64); override;
destructor Destroy; override;
function Keys: System.TArray<System.string>; override;
class function TryFindSessionID(const ASessionID: String): Boolean; override;
class procedure TryDeleteSessionID(const ASessionID: String); override;
end;
TMVCSessionFactory = class sealed
private
FRegisteredSessionTypes: TDictionary<string, TWebSessionClass>;
FRegisteredSessionTypes: TDictionary<string, TMVCWebSessionClass>;
protected
class var cInstance: TMVCSessionFactory;
constructor Create;
public
destructor Destroy; override;
procedure RegisterSessionType(const AName: string; AWebSessionClass: TWebSessionClass);
function CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TWebSession;
procedure RegisterSessionType(const AName: string; AWebSessionClass: TMVCWebSessionClass);
function CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TMVCWebSession;
function TryFindSessionID(const AName: string; const ASessionID: String): Boolean;
procedure TryDeleteSessionID(const AName: string; const ASessionID: String);
class function GetInstance: TMVCSessionFactory; static;
// class procedure DestroyInstance; static;
end;
function GlobalSessionList: TObjectDictionary<string, TWebSession>;
function GlobalSessionList: TObjectDictionary<string, TMVCWebSession>;
implementation
uses
System.IOUtils,
System.Classes,
MVCFramework.Serializer.Commons;
var
GlSessionList: TObjectDictionary<string, TWebSession> = nil;
GlSessionList: TObjectDictionary<string, TMVCWebSession> = nil;
GlLastSessionListClear: TDateTime;
GlCriticalSection: TCriticalSection;
function GlobalSessionList: TObjectDictionary<string, TWebSession>;
function GlobalSessionList: TObjectDictionary<string, TMVCWebSession>;
var
S: string;
begin
@ -111,7 +141,9 @@ begin
GlCriticalSection.Enter;
try
if not Assigned(GlSessionList) then
GlSessionList := TObjectDictionary<string, TWebSession>.Create([doOwnsValues]);
begin
GlSessionList := TObjectDictionary<string, TMVCWebSession>.Create([doOwnsValues]);
end;
finally
GlCriticalSection.Leave;
end;
@ -122,7 +154,7 @@ begin
TMonitor.Enter(GlSessionList);
try
for S in GlSessionList.Keys do
if TWebSession(GlSessionList.Items[S]).IsExpired then
if TMVCWebSession(GlSessionList.Items[S]).IsExpired then
GlSessionList.Remove(S);
GlLastSessionListClear := Now;
finally
@ -135,19 +167,19 @@ end;
{ TWebSession }
constructor TWebSession.Create(const ASessionId: string; const ATimeout: UInt64);
constructor TMVCWebSession.Create(const ASessionId: string; const ATimeout: UInt64);
begin
inherited Create;
FSessionId := ASessionId;
FTimeout := ATimeout;
end;
destructor TWebSession.Destroy;
destructor TMVCWebSession.Destroy;
begin
inherited Destroy;
end;
function TWebSession.IsExpired: Boolean;
function TMVCWebSession.IsExpired: Boolean;
begin
if (FTimeout = 0) then
Result := MinutesBetween(Now, LastAccess) > DEFAULT_SESSION_INACTIVITY
@ -155,31 +187,46 @@ begin
Result := MinutesBetween(Now, LastAccess) > FTimeout;
end;
procedure TWebSession.MarkAsUsed;
procedure TMVCWebSession.MarkAsUsed;
begin
FLastAccess := Now;
end;
function TWebSession.ToString: string;
procedure TMVCWebSession.SetLastAccess(Value: TDateTime);
begin
FLastAccess := Value;
end;
function TMVCWebSession.ToString: string;
begin
Result := '';
end;
class procedure TMVCWebSession.TryDeleteSessionID(const ASessionID: String);
begin
//do nothing
end;
class function TMVCWebSession.TryFindSessionID(const ASessionID: String): Boolean;
begin
Result := False;
end;
{ TWebSessionMemory }
constructor TWebSessionMemory.Create(const ASessionId: string; const ATimeout: UInt64);
constructor TMVCWebSessionMemory.Create(const ASessionId: string; const ATimeout: UInt64);
begin
inherited Create(ASessionId, ATimeout);
FData := TDictionary<string, string>.Create;
end;
destructor TWebSessionMemory.Destroy;
destructor TMVCWebSessionMemory.Destroy;
begin
FData.Free;
inherited Destroy;
end;
function TWebSessionMemory.GetItems(const AKey: string): string;
function TMVCWebSessionMemory.GetItems(const AKey: string): string;
begin
TMonitor.Enter(Self);
try
@ -190,7 +237,7 @@ begin
end;
end;
procedure TWebSessionMemory.SetItems(const AKey, AValue: string);
procedure TMVCWebSessionMemory.SetItems(const AKey, AValue: string);
begin
TMonitor.Enter(Self);
try
@ -200,7 +247,7 @@ begin
end;
end;
function TWebSessionMemory.ToString: string;
function TMVCWebSessionMemory.ToString: string;
var
LKey: string;
begin
@ -214,15 +261,15 @@ end;
constructor TMVCSessionFactory.Create;
begin
inherited Create;
FRegisteredSessionTypes := TDictionary<string, TWebSessionClass>.Create;
FRegisteredSessionTypes := TDictionary<string, TMVCWebSessionClass>.Create;
end;
function TMVCSessionFactory.CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TWebSession;
function TMVCSessionFactory.CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TMVCWebSession;
var
Clazz: TWebSessionClass;
Clazz: TMVCWebSessionClass;
begin
if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then
raise Exception.Create('Unknown application session type');
raise EMVCSession.Create('Unknown application session type: ' + AName);
Result := Clazz.Create(ASessionId, ATimeout);
end;
@ -241,14 +288,164 @@ begin
Result := cInstance;
end;
procedure TMVCSessionFactory.RegisterSessionType(const AName: string; AWebSessionClass: TWebSessionClass);
procedure TMVCSessionFactory.RegisterSessionType(const AName: string; AWebSessionClass: TMVCWebSessionClass);
begin
FRegisteredSessionTypes.AddOrSetValue(AName, AWebSessionClass);
end;
procedure TMVCSessionFactory.TryDeleteSessionID(const AName, ASessionID: String);
var
Clazz: TMVCWebSessionClass;
begin
if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then
raise EMVCSession.Create('Unknown application session type: ' + AName);
Clazz.TryDeleteSessionID(ASessionID);
end;
function TMVCSessionFactory.TryFindSessionID(const AName: string; const ASessionID: String): Boolean;
var
Clazz: TMVCWebSessionClass;
begin
if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then
raise EMVCSession.Create('Unknown application session type: ' + AName);
Result := Clazz.TryFindSessionID(ASessionID);
end;
{ TWebSessionMemoryController }
constructor TMVCWebSessionFile.Create(const SessionID: string; const Timeout: UInt64);
begin
inherited Create(SessionID, Timeout);
Data.OnValueNotify := OnValueNotify;
fSessionFolder := TPath.Combine(AppPath, 'sessions');
TDirectory.CreateDirectory(fSessionFolder);
LoadFromFile;
MarkAsUsed;
SaveToFile;
end;
destructor TMVCWebSessionFile.Destroy;
begin
inherited;
end;
procedure TMVCWebSessionFile.EndLoading;
begin
Data.OnValueNotify := OnValueNotify;
end;
class function TMVCWebSessionFile.GetFileName(const SessionFolder,
SessionID: String): String;
begin
Result := TPath.Combine(SessionFolder, SessionId);
end;
function TMVCWebSessionFile.GetFileName: String;
begin
Result := GetFileName(fSessionFolder, SessionId);
end;
function TMVCWebSessionFile.Keys: System.TArray<System.string>;
begin
Result := Data.Keys.ToArray;
end;
procedure TMVCWebSessionFile.LoadFromFile;
var
lFileName: String;
lFile: TStreamReader;
lLine: string;
lPieces: TArray<System.string>;
begin
lFileName := GetFileName;
if not TFile.Exists(lFileName) then
begin
Exit;
end;
//Log.Info('Loading session %s from %s', [SessionId, lFileName], 'file_session_events');
lFile := TFile.OpenText(lFileName);
try
StartLoading;
try
SetLastAccess(ISOTimeStampToDateTime(lFile.ReadLine));
while not lFile.EndOfStream do
begin
lLine := lFile.ReadLine;
lPieces := lLine.Split(['=']);
Data.Add(lPieces[0], lPieces[1]);
end;
finally
EndLoading;
end;
finally
lFile.Free;
end;
end;
procedure TMVCWebSessionFile.OnValueNotify(Sender: TObject; const Item: String;
Action: TCollectionNotification);
begin
if Action in [cnAdded, cnExtracted, cnRemoved] then
begin
//Log.Info('Saving session %s because item changed [%s]', [SessionId, Item], 'file_session_events');
SaveToFile;
end;
end;
procedure TMVCWebSessionFile.SaveToFile;
var
lFileName: String;
lPair: TPair<String, String>;
lFile: TStreamWriter;
begin
MarkAsUsed;
lFileName := GetFileName;
lFile := TFile.CreateText(lFileName);
try
lFile.WriteLine(DateTimeToISOTimeStamp(LastAccess));
for lPair in Data do
begin
lFile.WriteLine(String.Join('=', [lPair.Key, lPair.Value]));
end;
lFile.Close;
finally
lFile.Free;
end;
end;
procedure TMVCWebSessionFile.StartLoading;
begin
Data.OnValueNotify := nil;
end;
class procedure TMVCWebSessionFile.TryDeleteSessionID(const ASessionID: String);
var
lSessionFolder: string;
begin
inherited;
lSessionFolder := TPath.Combine(AppPath, 'sessions');
if TFile.Exists(GetFileName(lSessionFolder, ASessionID)) then
begin
TFile.Delete(GetFileName(lSessionFolder, ASessionID));
end;
end;
class function TMVCWebSessionFile.TryFindSessionID(
const ASessionID: String): Boolean;
var
lSessionFolder: string;
begin
inherited;
lSessionFolder := TPath.Combine(AppPath, 'sessions');
Result := TFile.Exists(GetFileName(lSessionFolder, ASessionID));
end;
initialization
TMVCSessionFactory.GetInstance.RegisterSessionType('memory', TWebSessionMemory);
TMVCSessionFactory.GetInstance.RegisterSessionType('memory', TMVCWebSessionMemory);
TMVCSessionFactory.GetInstance.RegisterSessionType('file', TMVCWebSessionFile);
GlCriticalSection := TCriticalSection.Create;
finalization

View File

@ -506,8 +506,8 @@ type
function IsValid: Boolean;
procedure Clear;
procedure SaveToSession(const AWebSession: TWebSession);
function LoadFromSession(const AWebSession: TWebSession): Boolean;
procedure SaveToSession(const AWebSession: TMVCWebSession);
function LoadFromSession(const AWebSession: TMVCWebSession): Boolean;
property UserName: string read FUserName write FUserName;
property Roles: TList<string> read FRoles;
@ -525,10 +525,10 @@ type
FIsSessionStarted: Boolean;
FSessionMustBeClose: Boolean;
FLoggedUser: TUser;
FWebSession: TWebSession;
FWebSession: TMVCWebSession;
FData: TMVCStringDictionary;
FIntfObject: IInterface;
function GetWebSession: TWebSession;
fIntfObject: IInterface;
function GetWebSession: TMVCWebSession;
function GetLoggedUser: TUser;
function GetParamsTable: TMVCRequestParamsTable;
procedure SetParamsTable(const AValue: TMVCRequestParamsTable);
@ -541,14 +541,14 @@ type
procedure BindToSession(const ASessionId: string);
function SendSessionCookie(const AContext: TWebContext): string;
function AddSessionToTheSessionList(const ASessionType, ASessionId: string;
const ASessionTimeout: Integer): TWebSession;
const ASessionTimeout: Integer): TMVCWebSession;
function GetData: TMVCStringDictionary;
public
constructor Create(const ARequest: TWebRequest; const AResponse: TWebResponse;
const AConfig: TMVCConfig; const ASerializers: TDictionary<string, IMVCSerializer>);
destructor Destroy; override;
procedure SessionStart; virtual;
procedure SessionStart(const SessionType: String); virtual;
procedure SessionStop(const ARaiseExceptionIfExpired: Boolean = True); virtual;
function SessionStarted: Boolean;
@ -560,7 +560,7 @@ type
property LoggedUser: TUser read GetLoggedUser;
property Request: TMVCWebRequest read FRequest;
property Response: TMVCWebResponse read FResponse;
property Session: TWebSession read GetWebSession;
property Session: TMVCWebSession read GetWebSession;
property Config: TMVCConfig read FConfig;
property Data: TMVCStringDictionary read GetData;
property CustomIntfObject: IInterface read GetIntfObject write SetIntfObject;
@ -772,7 +772,7 @@ type
private
FViewModel: TMVCViewDataObject;
FViewDataSets: TMVCViewDataSet;
function GetSession: TWebSession;
function GetSession: TMVCWebSession;
function GetViewData(const aModelName: string): TObject;
function GetViewDataset(const aDataSetName: string): TDataSet;
procedure SetViewData(const aModelName: string; const Value: TObject);
@ -808,7 +808,7 @@ type
/// </summary>
procedure LoadViewFragment(const AViewFragment: string);
function SessionAs<T: TWebSession>: T;
function SessionAs<T: TMVCWebSession>: T;
procedure RaiseSessionExpired; virtual;
// Avoiding mid-air collisions - support
@ -819,7 +819,7 @@ type
// Properties
property Context: TWebContext read GetContext write FContext;
property Session: TWebSession read GetSession;
property Session: TMVCWebSession read GetSession;
property ContentType: string read GetContentType write SetContentType;
property StatusCode: Integer read GetStatusCode write SetStatusCode;
procedure PushObjectToView(const aModelName: string; const AModel: TObject);
@ -1089,7 +1089,7 @@ type
function CustomExceptionHandling(const Ex: Exception; const AController: TMVCController;
const AContext: TWebContext): Boolean;
class function GetCurrentSession(const ASessionId: string;
const ARaiseExceptionIfExpired: Boolean = True): TWebSession; static;
const ARaiseExceptionIfExpired: Boolean = True): TMVCWebSession; static;
class function ExtractSessionIdFromWebRequest(const AWebRequest: TWebRequest): string; static;
class function SendSessionCookie(const AContext: TWebContext): string; overload; static;
class function SendSessionCookie(const AContext: TWebContext; const ASessionId: string): string;
@ -1101,9 +1101,8 @@ type
constructor Create(const AWebModule: TWebModule; const AConfigAction: TProc<TMVCConfig> = nil;
const ACustomLogger: ILogWriter = nil); reintroduce;
destructor Destroy; override;
function GetSessionBySessionId(const ASessionId: string): TWebSession;
function TryGetProtocolFilter<T: TCustomProtocolFilter>(var ProtocolFilter: T): Boolean;
function GetSessionBySessionId(const ASessionId: string): TMVCWebSession;
{ webcontext events}
procedure OnWebContextCreate(const WebContextCreateEvent: TWebContextCreateEvent);
@ -1153,43 +1152,77 @@ type
property message: string read FMessage write FMessage;
end;
// std responses
IMVCResponse = interface
['{9DFEC741-EE38-4AC9-9C2C-9EA0D15D08D5}']
function GetData: TObject;
function GetMessage: string;
function GetReasonString: string;
function GetStatusCode: Integer;
function GetIgnoredList: TMVCIgnoredList;
property StatusCode: Integer read GetStatusCode;
property ReasonString: string read GetReasonString;
property Message: string read GetMessage;
property Data: TObject read GetData;
end;
[MVCNameCase(ncLowerCase)]
TMVCResponse = class
TMVCResponse = class(TInterfacedObject, IMVCResponse)
private
FStatusCode: Integer;
FReasonString: string;
FMessage: string;
fStatusCode: Integer;
fReasonString: string;
fMessage: string;
fDataObject: TObject;
fIgnoredList: TMVCIgnoredList;
fObjectDictionary: IMVCObjectDictionary;
function GetData: TObject;
function GetMessage: string;
function GetReasonString: string;
function GetStatusCode: Integer;
procedure SetData(const Value: TObject);
procedure SetMessage(const Value: string);
procedure SetReasonString(const Value: string);
procedure SetStatusCode(const Value: Integer);
function GetObjectDictionary: IMVCObjectDictionary;
procedure SetObjectDictionary(const Value: IMVCObjectDictionary);
protected
{ protected declarations }
public
constructor Create; overload; virtual;
constructor Create(AStatusCode: Integer; AReasonString: string; AMessage: string); overload;
public
constructor Create(AStatusCode: Integer; AMessage: string; AReasonString: string = ''); overload;
constructor Create(AStatusCode: Integer; AData: TObject; AReasonString: string = ''); overload;
constructor Create(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: string = ''); overload;
destructor Destroy; override;
property StatusCode: Integer read FStatusCode write FStatusCode;
property ReasonString: string read FReasonString write FReasonString;
property Message: string read FMessage write FMessage;
property Data: TObject read fDataObject write fDataObject;
function GetIgnoredList: TMVCIgnoredList;
[MVCDoNotSerialize]
property StatusCode: Integer read GetStatusCode write SetStatusCode;
[MVCDoNotSerialize]
property ReasonString: string read GetReasonString write SetReasonString;
property Message: string read GetMessage write SetMessage;
property Data: TObject read GetData write SetData;
property ObjectDictionary: IMVCObjectDictionary read GetObjectDictionary write SetObjectDictionary;
end;
[MVCNameCase(ncLowerCase)]
TMVCErrorResponse = class(TMVCResponse)
private
FClassname: string;
FItems: TObjectList<TMVCErrorResponseItem>;
FAppErrorCode: Integer;
FDetailedMessage: string;
fClassname: string;
fItems: TObjectList<TMVCErrorResponseItem>;
fAppErrorCode: Integer;
fDetailedMessage: string;
procedure SetAppErrorCode(const Value: Integer);
public
constructor Create; override;
destructor Destroy; override;
property Classname: string read FClassname write FClassname;
property DetailedMessage: string read FDetailedMessage write FDetailedMessage;
property AppErrorCode: Integer read FAppErrorCode write SetAppErrorCode;
property Classname: string read fClassname write fClassname;
property DetailedMessage: string read fDetailedMessage write fDetailedMessage;
property AppErrorCode: Integer read fAppErrorCode write SetAppErrorCode;
[MVCListOf(TMVCErrorResponseItem)]
property Items: TObjectList<TMVCErrorResponseItem> read FItems;
property Items: TObjectList<TMVCErrorResponseItem> read fItems;
end;
// end - std responses
TMVCBaseViewEngine = class(TMVCBase)
@ -1224,7 +1257,13 @@ type
function IsShuttingDown: Boolean;
procedure EnterInShutdownState;
function CreateResponse(const StatusCode: UInt16; const ReasonString: string;
const Message: string = ''): TMVCResponse;
const Message: string = ''): TMVCResponse; deprecated 'Use MVCResponse()';
// std responses
function MVCResponse(AStatusCode: Integer; AMessage: string = ''; AReasonString: string = ''): IMVCResponse; overload;
function MVCResponse(AStatusCode: Integer; AData: TObject; AReasonString: string = ''): IMVCResponse; overload;
function MVCResponse(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: string = ''): IMVCResponse; overload;
// end - std responses
implementation
@ -1992,7 +2031,7 @@ begin
Result := (not UserName.IsEmpty) and (LoggedSince > 0);
end;
function TUser.LoadFromSession(const AWebSession: TWebSession): Boolean;
function TUser.LoadFromSession(const AWebSession: TMVCWebSession): Boolean;
var
SerObj: string;
Pieces: TArray<string>;
@ -2016,7 +2055,7 @@ begin
end;
end;
procedure TUser.SaveToSession(const AWebSession: TWebSession);
procedure TUser.SaveToSession(const AWebSession: TMVCWebSession);
var
LRoles: string;
begin
@ -2044,9 +2083,9 @@ end;
{ TWebContext }
function TWebContext.AddSessionToTheSessionList(const ASessionType, ASessionId: string;
const ASessionTimeout: Integer): TWebSession;
const ASessionTimeout: Integer): TMVCWebSession;
var
Session: TWebSession;
Session: TMVCWebSession;
begin
if (Trim(ASessionType) = EmptyStr) then
raise EMVCException.Create('Empty Session Type');
@ -2218,16 +2257,35 @@ begin
Result := FRequest.ParamsTable;
end;
function TWebContext.GetWebSession: TWebSession;
function TWebContext.GetWebSession: TMVCWebSession;
var
lSessionIDFromRequest: string;
lSessionType: String;
begin
if not Assigned(FWebSession) then
begin
FWebSession := TMVCEngine.GetCurrentSession(
TMVCEngine.ExtractSessionIdFromWebRequest(FRequest.RawWebRequest), False);
lSessionIDFromRequest := TMVCEngine.ExtractSessionIdFromWebRequest(FRequest.RawWebRequest);
FWebSession := TMVCEngine.GetCurrentSession(lSessionIDFromRequest, False);
if not Assigned(FWebSession) then
SessionStart
begin
lSessionType := Config[TMVCConfigKey.SessionType];
if not TMVCSessionFactory.GetInstance.TryFindSessionID(lSessionType, lSessionIDFromRequest) then
begin
SessionStart(lSessionType);
end
else
begin
FWebSession := AddSessionToTheSessionList(
lSessionType,
lSessionIDFromRequest,
StrToInt(Config[TMVCConfigKey.SessionTimeout]));
TMVCEngine.SendSessionCookie(Self, FWebSession.SessionId);
end;
end
else
begin
TMVCEngine.SendSessionCookie(Self, FWebSession.SessionId);
end;
end;
Result := FWebSession;
Result.MarkAsUsed;
@ -2255,14 +2313,14 @@ begin
Result := FSessionMustBeClose;
end;
procedure TWebContext.SessionStart;
procedure TWebContext.SessionStart(const SessionType: String);
var
ID: string;
begin
if not Assigned(FWebSession) then
begin
ID := TMVCEngine.SendSessionCookie(Self);
FWebSession := AddSessionToTheSessionList(Config[TMVCConfigKey.SessionType], ID,
FWebSession := AddSessionToTheSessionList(SessionType, ID,
StrToInt64(Config[TMVCConfigKey.SessionTimeout]));
FIsSessionStarted := True;
FSessionMustBeClose := False;
@ -2305,10 +2363,20 @@ begin
begin
raise EMVCSessionExpiredException.Create('Session not started');
end;
GlobalSessionList.Remove(SId);
if SId <> '' then
begin
FWebSession := nil;
try
TMVCSessionFactory.GetInstance.TryDeleteSessionID(Config[TMVCConfigKey.SessionType], SId);
except
on E: Exception do
begin
LogException(E, 'Cannot delete session file for sessionid: ' + SId);
end;
end;
end;
finally
TMonitor.Exit(GlobalSessionList);
@ -2446,7 +2514,6 @@ begin
{end - filters}
FControllers := TObjectList<TMVCControllerDelegate>.Create(True);
FSavedOnBeforeDispatch := nil;
WebRequestHandler.CacheConnections := True;
WebRequestHandler.MaxConnections := 4096;
@ -2569,66 +2636,6 @@ begin
end;
end;
//procedure TMVCEngine.ExecuteAfterControllerActionMiddleware(const AContext: TWebContext;
// const AControllerQualifiedClassName: string; const AActionName: string;
// const AHandled: Boolean);
//var
// I: Integer;
//begin
// for I := 0 to FMiddlewares.Count - 1 do
// begin
// FMiddlewares[I].OnAfterControllerAction(AContext, AControllerQualifiedClassName, AActionName, AHandled);
// end;
//end;
//procedure TMVCEngine.ExecuteAfterRoutingMiddleware(const AContext: TWebContext;
// const AHandled: Boolean);
//var
// I: Integer;
//begin
// for I := 0 to FMiddlewares.Count - 1 do
// begin
// FMiddlewares[I].OnAfterRouting(AContext, AHandled);
// end;
//end;
//procedure TMVCEngine.ExecuteBeforeControllerActionMiddleware(const AContext: TWebContext;
// const AControllerQualifiedClassName: string; const AActionName: string; var AHandled: Boolean);
//var
// Middleware: IMVCMiddleware;
//begin
// if not AHandled then
// begin
// for Middleware in FMiddlewares do
// begin
// Middleware.OnBeforeControllerAction(AContext, AControllerQualifiedClassName, AActionName,
// AHandled);
// if AHandled then
// begin
// Break;
// end;
// end;
// end;
//end;
//procedure TMVCEngine.ExecuteBeforeRoutingMiddleware(const AContext: TWebContext;
// var AHandled: Boolean);
//var
// Middleware: IMVCMiddleware;
//begin
// if not AHandled then
// begin
// for Middleware in FMiddlewares do
// begin
// Middleware.OnBeforeRouting(AContext, AHandled);
// if AHandled then
// begin
// Break;
// end;
// end;
// end;
//end;
class function TMVCEngine.ExtractSessionIdFromWebRequest(const AWebRequest: TWebRequest): string;
begin
Result := AWebRequest.CookieFields.Values[TMVCConstants.SESSION_TOKEN_NAME];
@ -2642,8 +2649,11 @@ begin
FWebModule.BeforeDispatch := OnBeforeDispatch;
end;
class function TMVCEngine.GetCurrentSession(const ASessionId: string; const ARaiseExceptionIfExpired: Boolean): TWebSession;
var lSessionList: TObjectDictionary<string, TWebSession>;
class function TMVCEngine.GetCurrentSession(
const ASessionId: string;
const ARaiseExceptionIfExpired: Boolean): TMVCWebSession;
var
lSessionList: TObjectDictionary<string, TMVCWebSession>;
begin
Result := nil;
lSessionList := GlobalSessionList;
@ -2677,7 +2687,7 @@ begin
end;
end;
function TMVCEngine.GetSessionBySessionId(const ASessionId: string): TWebSession;
function TMVCEngine.GetSessionBySessionId(const ASessionId: string): TMVCWebSession;
begin
Result := TMVCEngine.GetCurrentSession(ASessionId, False);
if Assigned(Result) then
@ -2866,10 +2876,14 @@ begin
end;
class function TMVCEngine.SendSessionCookie(const AContext: TWebContext): string;
var SId: string;
var
SId: string;
begin
SId := StringReplace(StringReplace(StringReplace('DT' + GUIDToString(TGUID.NewGuid), '}', '', []),
'{', '', []), '-', '', [rfReplaceAll]);
SId := StringReplace(StringReplace(StringReplace(
'DT' + GUIDToString(TGUID.NewGuid) + GUIDToString(TGUID.NewGuid),
'}', '', [rfReplaceAll]),
'{', '', [rfReplaceAll]),
'-', '', [rfReplaceAll]);
Result := SendSessionCookie(AContext, SId);
end;
@ -3126,7 +3140,7 @@ begin
Result := Context.Request.GetHeader('If-Match');
end;
function TMVCController.GetSession: TWebSession;
function TMVCController.GetSession: TMVCWebSession;
begin
Result := GetContext.Session;
end;
@ -3372,8 +3386,9 @@ begin
GetContext.Response.RawWebResponse.FreeContentStream := True;
end;
function TMVCRenderer.Serializer(const AContentType: string;
const ARaiseExceptionIfNotExists: Boolean): IMVCSerializer;
function TMVCRenderer.Serializer(
const AContentType: string;
const ARaiseExceptionIfNotExists: Boolean): IMVCSerializer;
var lContentMediaType: string;
lContentCharSet: string;
begin
@ -3530,6 +3545,7 @@ procedure TMVCRenderer.Render(
const AObject: IInterface;
const ASerializationAction: TMVCSerializationAction);
begin
{TODO -oDanieleT -cGeneral : Handle StatusCode}
Render(TObject(AObject), False, ASerializationAction);
end;
@ -3759,8 +3775,8 @@ begin
begin
try
GetContext.Response.StatusCode := AResponse.StatusCode;
GetContext.Response.ReasonString := HTTP_STATUS.ReasonStringFor(AResponse.StatusCode);
Render(AResponse, False, stProperties);
GetContext.Response.ReasonString := AResponse.ReasonString;
Render(AResponse, False, stProperties, nil, AResponse.GetIgnoredList);
finally
if AOwns then
AResponse.Free;
@ -3810,6 +3826,7 @@ constructor TMVCResponse.Create;
begin
inherited Create;
fDataObject := nil;
fMessage := '';
end;
constructor TMVCErrorResponse.Create;
@ -3818,12 +3835,32 @@ begin
FItems := TObjectList<TMVCErrorResponseItem>.Create(True);
end;
constructor TMVCResponse.Create(AStatusCode: Integer; AReasonString, AMessage: string);
constructor TMVCResponse.Create(AStatusCode: Integer; AMessage: string; AReasonString: string);
begin
Create;
StatusCode := AStatusCode;
ReasonString := AReasonString;
message := AMessage;
fStatusCode := AStatusCode;
fMessage := AMessage;
fReasonString := AReasonString;
fIgnoredList := ['Data', 'ObjectDictionary'];
end;
constructor TMVCResponse.Create(AStatusCode: Integer; AData: TObject; AReasonString: string);
begin
Create;
fStatusCode := AStatusCode;
fDataObject := AData;
fReasonString := AReasonString;
fIgnoredList := ['Message', 'ObjectDictionary'];
end;
constructor TMVCResponse.Create(AStatusCode: Integer;
AObjectDictionary: IMVCObjectDictionary; AReasonString: string);
begin
Create;
fStatusCode := AStatusCode;
fObjectDictionary := AObjectDictionary;
fReasonString := AReasonString;
fIgnoredList := ['Message', 'Data'];
end;
destructor TMVCResponse.Destroy;
@ -3832,6 +3869,64 @@ begin
inherited;
end;
function TMVCResponse.GetData: TObject;
begin
Result := fDataObject;
end;
function TMVCResponse.GetIgnoredList: TMVCIgnoredList;
begin
Result := fIgnoredList;
end;
function TMVCResponse.GetMessage: string;
begin
Result := fMessage;
end;
function TMVCResponse.GetObjectDictionary: IMVCObjectDictionary;
begin
Result := fObjectDictionary;
end;
function TMVCResponse.GetReasonString: string;
begin
if fReasonString.IsEmpty then
Result := HTTP_STATUS.ReasonStringFor(fStatusCode)
else
Result := fReasonString;
end;
function TMVCResponse.GetStatusCode: Integer;
begin
Result := fStatusCode;
end;
procedure TMVCResponse.SetData(const Value: TObject);
begin
fDataObject := Value;
end;
procedure TMVCResponse.SetMessage(const Value: string);
begin
fMessage := Value;
end;
procedure TMVCResponse.SetObjectDictionary(const Value: IMVCObjectDictionary);
begin
fObjectDictionary := Value;
end;
procedure TMVCResponse.SetReasonString(const Value: string);
begin
fReasonString := Value;
end;
procedure TMVCResponse.SetStatusCode(const Value: Integer);
begin
fStatusCode := Value;
end;
destructor TMVCErrorResponse.Destroy;
begin
FItems.Free;
@ -4054,6 +4149,24 @@ procedure TCustomControllerFilter.SetNext(NextFilter: IControllerFilter);
begin
fNext := NextFilter;
end;
//=======
// std responses
function MVCResponse(AStatusCode: Integer; AMessage: string; AReasonString: string): IMVCResponse; overload;
begin
Result := TMVCResponse.Create(AStatusCode, AMessage, AReasonString);
end;
function MVCResponse(AStatusCode: Integer; AData: TObject; AReasonString: string): IMVCResponse; overload;
begin
Result := TMVCResponse.Create(AStatusCode, AData, AReasonString);
end;
function MVCResponse(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: string): IMVCResponse; overload;
begin
Result := TMVCResponse.Create(AStatusCode, AObjectDictionary, AReasonString);
end;
// end - std responses
initialization

View File

@ -70,12 +70,20 @@ type
[Test]
procedure TestSelectWithExceptions;
[Test]
procedure TestNamedQuerySQL;
[Test]
procedure TestNamedQuerySQLByBackEnd;
[Test]
procedure TestStore;
[Test]
procedure TestLifeCycle;
[Test]
procedure TestRQL;
[Test]
procedure TestNamedQueryRQL;
[Test]
procedure TestNamedQueryRQLWithExceptions;
[Test]
procedure TestRQLWithMVCNameAsAttribute;
[Test]
procedure TestRQLWithBoolean;
@ -1170,6 +1178,68 @@ begin
Assert.AreEqual(Trunc(20 * 30), TMVCActiveRecord.Count(TCustomerWithLF));
end;
procedure TTestActiveRecordBase.TestNamedQueryRQL;
var
lCustomers: TObjectList<TCustomer>;
begin
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer));
LoadData;
lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('CityRomeOrLondon', [], MAXINT);
try
Assert.AreEqual(240, lCustomers.Count);
for var lCustomer in lCustomers do
begin
Assert.IsMatch('^(Rome|London)$', lCustomer.City);
end;
finally
lCustomers.Free;
end;
TMVCActiveRecord.DeleteRQLByNamedQuery<TCustomer>('CityRomeOrLondon', []);
Assert.AreEqual(Int64(0), TMVCActiveRecord.CountRQLByNamedQuery<TCustomer>('CityRomeOrLondon', []));
end;
procedure TTestActiveRecordBase.TestNamedQueryRQLWithExceptions;
begin
Assert.WillRaiseWithMessage(
procedure
begin
TMVCActiveRecord.SelectRQLByNamedQuery<TCustomer>('WrongQueryName', [1,2,3], MAXINT);
end, nil, 'NamedRQLQuery not found: WrongQueryName');
Assert.WillRaiseWithMessage(
procedure
begin
TMVCActiveRecord.DeleteRQLByNamedQuery<TCustomer>('WrongQueryName', []);
end, nil, 'NamedRQLQuery not found: WrongQueryName');
end;
procedure TTestActiveRecordBase.TestNamedQuerySQL;
begin
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer));
LoadData;
var lCustomers := TMVCActiveRecord.SelectByNamedQuery<TCustomer>('ByTwoCities', ['Rome', 'London'], [ftString, ftString]);
try
Assert.AreEqual(240, lCustomers.Count);
for var lCustomer in lCustomers do
begin
Assert.IsMatch('^(Rome|London)$', lCustomer.City);
end;
finally
lCustomers.Free;
end;
end;
procedure TTestActiveRecordBase.TestNamedQuerySQLByBackEnd;
begin
var lList := TMVCActiveRecord.SelectByNamedQuery<TDummyEntity>('get_backend_name', [],[]);
try
Assert.AreEqual(1, lList.Count);
Assert.AreEqual(lList.First.GetBackEnd, lList.First.BackEndName);
finally
lList.Free;
end;
end;
procedure TTestActiveRecordBase.TestNullables;
var
lTest: TNullablesTest;

View File

@ -101,6 +101,8 @@ const
type
[MVCTable('customers')]
[MVCNamedRQLQuery('CityRomeOrLondon','or(eq(City, "Rome"),eq(City, "London"))')]
[MVCNamedSQLQuery('ByTwoCities','select * from customers where city = ? or city = ?')]
TCustomer = class(TMVCActiveRecord)
private
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
@ -661,6 +663,19 @@ type
destructor Destroy; override;
end;
[MVCEntityActions([eaRetrieve])]
[MVCNamedSQLQuery('get_backend_name', 'select ''firebird'' backendname from rdb$database', TMVCActiveRecordBackEnd.FirebirdSQL)]
[MVCNamedSQLQuery('get_backend_name', 'select ''postgresql'' backendname', TMVCActiveRecordBackEnd.PostgreSQL)]
[MVCNamedSQLQuery('get_backend_name', 'select ''sqlite'' backendname', TMVCActiveRecordBackEnd.SQLite)]
TDummyEntity = class(TMVCActiveRecord)
private
[MVCTableField('backendname')]
FBackEndName: String;
procedure SetBackEndName(const Value: String);
public
property BackEndName: String read FBackEndName write SetBackEndName;
end;
function GetMyObject: TMyObject;
function GetMyObjectWithTValue: TMyObjectWithTValue;
function GetMyObjectWithStream: TMyStreamObject;
@ -1432,6 +1447,13 @@ begin
end;
{ TDummyEntity }
procedure TDummyEntity.SetBackEndName(const Value: String);
begin
FBackEndName := Value;
end;
initialization
ActiveRecordMappingRegistry.AddEntity('customers', TCustomer);

View File

@ -38,43 +38,6 @@ uses
type
[TestFixture]
TTestMappers = class(TObject)
protected
[Test]
procedure SameFishesDataSet(ds, ds2: TDataSet);
public
// procedure TestObjectToJSONObject;
// procedure TestObjectListToJSONArray;
// procedure TestObjectToJSONObject_Generics;
// procedure TestWrappedListToJSONArray;
// procedure TestJSONObjectToObjectAndBack;
// procedure TestLoadJSONObjectToObjectAndBack;
// procedure TestSerializeUsingProperties;
// procedure TestSerializeUsingFields;
// procedure TestSerializeUsingFieldsComplexObject;
// procedure TestSerializeUsingFieldsComplexObject2;
// procedure TestSerializeUsingFieldsWithNotExixtentPropetyInJSONObject;
// procedure TestComplexObjectToJSONObjectAndBack;
// procedure TestComplexObjectToJSONObjectAndBackWithNilReference;
// procedure TestDataSetToJSONObject;
// procedure TestDataSetToJSONObjectWithNulls;
// procedure TestDataSetToJSONObjectFieldPolicyLowerCase;
// procedure TestDataSetToJSONObjectFieldPolicyUpperCase;
// procedure TestDataSetToJSONObjectFieldPolicyAsIsCase;
// procedure TestDataSetToJSONArray;
// procedure TestObjectToJSONObjectAndBackWithStringStreamUTF16;
// procedure TestObjectToJSONObjectAndBackWithStringStreamUTF8;
// procedure TestObjectToJSONObjectAndBackWithStream;
// procedure TestJSONArrayToObjectListNoGenerics;
// procedure TestJSONArrayToObjectListNoGenericsWrappedList;
// procedure TestCheckMapperSerializeAsStringIsEmptyStrIfObjIsNil;
// procedure TestJSONObjectToObjectWithNullInJSONString;
// procedure TestJSONObjectStringToObject;
// procedure TestJSONObjectStringToObjectWithWrongJSON;
end;
[TestFixture]
TTestRouting = class(TObject)
private
@ -381,18 +344,6 @@ begin
end;
end;
procedure TTestMappers.SameFishesDataSet(ds, ds2: TDataSet);
begin
Assert.areEqual(ds.FieldByName('Species No').AsInteger, ds2.FieldByName('Species No').AsInteger);
Assert.areEqual(ds.FieldByName('Category').AsString, ds2.FieldByName('Category').AsString);
Assert.areEqual(ds.FieldByName('Common_Name').AsString, ds2.FieldByName('Common_Name').AsString);
Assert.areEqual(ds.FieldByName('Species Name').AsString, ds2.FieldByName('Species Name').AsString);
Assert.areEqual(ds.FieldByName('Length (cm)').AsString, ds2.FieldByName('Length (cm)').AsString);
Assert.areEqual(ds.FieldByName('Length_In').AsInteger, ds2.FieldByName('Length_In').AsInteger);
Assert.areEqual(ds.FieldByName('Notes').AsString, ds2.FieldByName('Notes').AsString);
Assert.areEqual(ds.FieldByName('Graphic').AsString, ds2.FieldByName('Graphic').AsString);
end;
procedure TTestRouting.SetUp;
begin
FControllers := TObjectList<TMVCControllerDelegate>.Create;

View File

@ -298,6 +298,22 @@ type
[Test]
procedure TestViewDataViewDataSet;
// test functional actions
[Test]
procedure TestFuncActionGetSingleRecord;
[Test]
procedure TestFuncActionGetMultipleRecords;
[Test]
procedure TestFuncActionGetDatasetSingle;
[Test]
procedure TestFuncActionGetDatasetMultiple;
[Test]
procedure TestFuncActionGetComplexObject;
// test issues
[Test]
[Category('renders')]
@ -1068,12 +1084,11 @@ var
begin
res := RESTClient.Get('/exception/emvcexception1');
Assert.areEqual<Integer>(HTTP_STATUS.InternalServerError, res.StatusCode);
Assert.areEqual('Internal Server Error', res.StatusText);
lJSON := StrToJSONObject(res.Content);
try
Assert.areEqual<string>('message', lJSON.S['message'], lJSON.ToJSON());
Assert.areEqual<string>('EMVCException', lJSON.S['classname'], lJSON.ToJSON());
Assert.areEqual<Integer>(500, lJSON.I['statuscode'], lJSON.ToJSON());
Assert.areEqual<string>('Internal Server Error', lJSON.S['reasonstring'], lJSON.ToJSON());
Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON());
Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON());
finally
@ -1089,12 +1104,11 @@ var
begin
res := RESTClient.Get('/exception/emvcexception2');
Assert.areEqual<Integer>(HTTP_STATUS.BadRequest, res.StatusCode);
Assert.areEqual('Bad Request', res.StatusText);
lJSON := StrToJSONObject(res.Content);
try
Assert.areEqual<string>('message', lJSON.S['message'], lJSON.ToJSON());
Assert.areEqual<string>('EMVCException', lJSON.S['classname'], lJSON.ToJSON());
Assert.areEqual<Integer>(HTTP_STATUS.BadRequest, lJSON.I['statuscode'], lJSON.ToJSON());
Assert.areEqual<string>('Bad Request', lJSON.S['reasonstring'], lJSON.ToJSON());
Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON());
Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON());
finally
@ -1109,12 +1123,11 @@ var
begin
res := RESTClient.Get('/exception/emvcexception3');
Assert.areEqual<Integer>(HTTP_STATUS.Created, res.StatusCode);
Assert.areEqual('Created', res.StatusText);
lJSON := StrToJSONObject(res.Content);
try
Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON());
Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON());
Assert.areEqual(HTTP_STATUS.Created, lJSON.I['statuscode'], lJSON.ToJSON());
Assert.areEqual('Created', lJSON.S['reasonstring'], lJSON.ToJSON());
Assert.areEqual(999, lJSON.I['apperrorcode'], lJSON.ToJSON());
Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON());
Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON());
@ -1130,13 +1143,12 @@ var
begin
res := RESTClient.Get('/exception/emvcexception4');
Assert.areEqual<Integer>(HTTP_STATUS.Created, res.StatusCode);
Assert.areEqual('Created', res.StatusText);
lJSON := StrToJSONObject(res.Content);
try
Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON());
Assert.areEqual('detailedmessage', lJSON.S['detailedmessage'], lJSON.ToJSON());
Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON());
Assert.areEqual(HTTP_STATUS.Created, lJSON.I['statuscode'], lJSON.ToJSON());
Assert.areEqual('Created', lJSON.S['reasonstring'], lJSON.ToJSON());
Assert.areEqual(999, lJSON.I['apperrorcode'], lJSON.ToJSON());
Assert.areEqual(2, lJSON.A['items'].Count, lJSON.ToJSON());
Assert.areEqual('erritem1', lJSON.A['items'].O[0].S['message'], lJSON.ToJSON());
@ -1443,6 +1455,118 @@ begin
Assert.areEqual('This is a TEXT file', lRes.Content, '/static/folder1.html');
end;
procedure TServerTest.TestFuncActionGetComplexObject;
var
c1: IMVCRESTClient;
lRes: IMVCRESTResponse;
begin
c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999);
lRes := c1.Get('/api/v1/actionresult/complex');
Assert.areEqual(200, lRes.StatusCode);
var lJSON := lRes.ToJSONObject;
try
Assert.AreEqual(3, lJSON.Count);
Assert.IsTrue(lJSON.Types['value'] = jdtInt);
Assert.IsTrue(lJSON.Types['person'] = jdtObject);
Assert.IsTrue(lJSON.Types['people'] = jdtArray);
Assert.AreEqual(6, lJSON.O['person'].Count);
Assert.AreEqual(3, lJSON.A['people'].Count);
Assert.AreEqual(6, lJSON.A['people'][0].ObjectValue.Count);
Assert.AreEqual(6, lJSON.A['people'][1].ObjectValue.Count);
Assert.AreEqual(6, lJSON.A['people'][2].ObjectValue.Count);
finally
lJSON.Free;
end;
end;
procedure TServerTest.TestFuncActionGetDatasetMultiple;
var
c1: IMVCRESTClient;
lRes: IMVCRESTResponse;
begin
c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999);
lRes := c1.Get('/api/v1/actionresult/dataset/multiple');
Assert.areEqual(200, lRes.StatusCode);
var lJSON := lRes.ToJSONObject;
try
Assert.AreEqual(2, lJSON.Count);
Assert.IsTrue(lJSON.Contains('ds1'));
Assert.IsTrue(lJSON.Contains('ds2'));
Assert.AreEqual(15, lJSON.A['ds1'].Count);
Assert.AreEqual(15, lJSON.A['ds2'].Count);
finally
lJSON.Free;
end;
end;
procedure TServerTest.TestFuncActionGetDatasetSingle;
var
c1: IMVCRESTClient;
lRes: IMVCRESTResponse;
begin
c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999);
lRes := c1.Get('/api/v1/actionresult/dataset/single');
Assert.areEqual(200, lRes.StatusCode);
var lJSON := lRes.ToJSONArray;
try
Assert.AreEqual(15, lJSON.Count);
for var I := 0 to lJSON.Count - 1 do
begin
Assert.IsTrue(lJSON[I].Typ = jdtObject);
Assert.AreEqual(12, lJSON[I].ObjectValue.Count);
end;
finally
lJSON.Free;
end;
end;
procedure TServerTest.TestFuncActionGetMultipleRecords;
var
c1: IMVCRESTClient;
lRes: IMVCRESTResponse;
begin
c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999);
lRes := c1.Get('/api/v1/actionresult/records/multiple');
Assert.areEqual(200, lRes.StatusCode);
var lJSON := lRes.ToJSONArray;
try
Assert.AreEqual(3, lJSON.Count);
Assert.AreEqual('Daniele', lJSON[0].S['firstName']);
Assert.AreEqual('Teti', lJSON[0].S['lastName']);
Assert.AreEqual(20, lJSON[0].I['age']);
Assert.AreEqual('Daniele', lJSON[1].S['firstName']);
Assert.AreEqual('Teti', lJSON[1].S['lastName']);
Assert.AreEqual(30, lJSON[1].I['age']);
Assert.AreEqual('Daniele', lJSON[2].S['firstName']);
Assert.AreEqual('Teti', lJSON[2].S['lastName']);
Assert.AreEqual(40, lJSON[2].I['age']);
finally
lJSON.Free;
end;
end;
procedure TServerTest.TestFuncActionGetSingleRecord;
var
c1: IMVCRESTClient;
lRes: IMVCRESTResponse;
begin
c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999);
lRes := c1.Get('/api/v1/actionresult/records/single');
Assert.areEqual(200, lRes.StatusCode);
var lJSON := lRes.ToJSONObject;
try
Assert.AreEqual(3, lJSON.Count);
Assert.AreEqual('Daniele', lJSON.S['firstName']);
Assert.AreEqual('Teti', lJSON.S['lastName']);
Assert.AreEqual(99, lJSON.I['age']);
finally
lJSON.Free;
end;
end;
procedure TServerTest.TestGetImagePng;
var
c1: IMVCRESTClient;

View File

@ -34,7 +34,8 @@ uses
FireDAC.Comp.Client,
System.Generics.Collections,
Data.DB,
BusinessObjectsU;
BusinessObjectsU, MVCFramework.Serializer.Commons, System.Classes,
System.UITypes;
type
@ -46,9 +47,10 @@ type
fDataSet: TFDMemTable;
protected
procedure MVCControllerAfterCreate; override;
function GetDataSet: TDataSet;
procedure MVCControllerBeforeDestroy; override;
public
class function GetDataSet: TDataSet;
[MVCPath('/req/with/params/($par1)/($par2)/($par3)')]
[MVCHTTPMethod([httpGET, httpDELETE])]
procedure ReqWithParams;
@ -412,6 +414,117 @@ type
procedure Action1or2;
end;
// action result types
[MVCNameCase(ncLowerCase)]
TSum = class
private
fValue: Integer;
public
property Value: Integer read fValue write fValue;
end;
[MVCNameCase(ncLowerCase)]
TComplexObject = class
private
fValue: Integer;
FPeople: TPeople;
FPerson: TPerson;
procedure SetPeople(const Value: TPeople);
procedure SetPerson(const Value: TPerson);
public
destructor Destroy; override;
property Value: Integer read fValue write fValue;
property Person: TPerson read FPerson write SetPerson;
property People: TPeople read FPeople write SetPeople;
end;
[MVCNameCase(ncCamelCase)]
TPersonRec = record
FirstName, LastName: String;
Age: Integer;
class function Create: TPersonRec; static;
end;
// action result types - end
[MVCPath('/api/v1/actionresult')]
TTestActionResultController = class(TMVCController)
public
{ actions returning records }
[MVCPath('/sums/($a)/($b)')]
[MVCHTTPMethod([httpGET])]
function GetObject(a,b: Integer): TSum;
[MVCPath('/records/single')]
function GetSingleRecord: TPersonRec;
[MVCPath('/records/multiple')]
function GetMultipleRecords: TArray<TPersonRec>;
[MVCPath('/complex')]
[MVCHTTPMethod([httpGET])]
function GetComplexObject: TComplexObject;
[MVCPath('/people')]
[MVCHTTPMethod([httpGET])]
function GetPeople: TObjectList<TPerson>;
[MVCPath('/people/($id)')]
[MVCHTTPMethod([httpGET])]
function GetPerson(id: Integer): IPerson;
[MVCPath('/photo')]
[MVCHTTPMethod([httpGET])]
function GetPhoto: TStream;
[MVCPath('/string')]
[MVCHTTPMethod([httpGET])]
function GetString: String;
[MVCPath('/enum')]
[MVCHTTPMethod([httpGET])]
function GetEnum: TFontStyle;
[MVCPath('/bool')]
[MVCHTTPMethod([httpGET])]
function GetBool: Boolean;
[MVCPath('/float')]
[MVCHTTPMethod([httpGET])]
function GetFloat: Double;
[MVCPath('/strdict')]
[MVCHTTPMethod([httpGET])]
function GetStrDict: TMVCStringDictionary;
[MVCPath('/TSimpleRecord')]
[MVCHTTPMethod([httpGET])]
function GetTSimpleRecord: TSimpleRecord;
[MVCPath('/ArrayOf/TSimpleRecord')]
[MVCHTTPMethod([httpGET])]
function GetArrayOfTSimpleRecord: TArray<TSimpleRecord>;
[MVCPath('/TComplexRecord')]
[MVCHTTPMethod([httpGET])]
function GetTComplexRecord: TComplexRecord;
[MVCPath('/ArrayOf/TComplexRecord')]
[MVCHTTPMethod([httpGET])]
function GetArrayOfTComplexRecord: TComplexRecordArray;
[MVCPath('/dataset/single')]
[MVCHTTPMethod([httpGET])]
function GetDataSetSingle: TDataSet;
[MVCPath('/dataset/multiple')]
[MVCHTTPMethod([httpGET])]
function GetDataSetMultiple: IMVCObjectDictionary;
end;
implementation
uses
@ -419,11 +532,9 @@ uses
System.JSON,
Web.HTTPApp,
Generics.Collections,
MVCFramework.Serializer.Commons,
MVCFramework.Serializer.Defaults,
MVCFramework.DuckTyping,
System.IOUtils,
System.Classes, MVCFramework.Tests.Serializer.Entities;
System.IOUtils, MVCFramework.Tests.Serializer.Entities, System.DateUtils;
{ TTestServerController }
@ -512,7 +623,7 @@ begin
end;
function TTestServerController.GetDataSet: TDataSet;
class function TTestServerController.GetDataSet: TDataSet;
begin
Result := TFDMemTable.Create(nil);
TFDMemTable(Result).LoadFromFile(TPath.Combine(AppPath, 'customers.json'));
@ -1226,4 +1337,150 @@ begin
Render(HTTP_STATUS.OK);
end;
{ TTestActionResultController }
function TTestActionResultController.GetArrayOfTComplexRecord: TComplexRecordArray;
begin
SetLength(Result,3);
Result[0] := TComplexRecord.Create;
Result[1] := TComplexRecord.Create;
Result[2] := TComplexRecord.Create;
Result[0].StringProperty := 'item 0';
Result[1].StringProperty := 'item 1';
Result[2].StringProperty := 'item 2';
end;
function TTestActionResultController.GetArrayOfTSimpleRecord: TArray<TSimpleRecord>;
begin
SetLength(Result, 3);
Result[0] := TSimpleRecord.Create;
Result[1] := TSimpleRecord.Create;
Result[2] := TSimpleRecord.Create;
end;
function TTestActionResultController.GetBool: Boolean;
begin
Result := True;
end;
function TTestActionResultController.GetComplexObject: TComplexObject;
begin
Result := TComplexObject.Create;
Result.Value := 1234;
Result.Person := TPerson.GetNew('Danielem', 'Teti', EncodeDate(1920,12,23), True);
Result.People := TPerson.GetList();
end;
function TTestActionResultController.GetDataSetMultiple: IMVCObjectDictionary;
begin
Result :=
ObjectDict()
.Add('ds1', TTestServerController.GetDataSet)
.Add('ds2', TTestServerController.GetDataSet);
end;
function TTestActionResultController.GetDataSetSingle: TDataSet;
begin
Result := TTestServerController.GetDataSet;
end;
function TTestActionResultController.GetEnum: TFontStyle;
begin
Result := TFontStyle.fsBold;
end;
function TTestActionResultController.GetFloat: Double;
begin
Result := 3.1415;
end;
function TTestActionResultController.GetMultipleRecords: TArray<TPersonRec>;
begin
SetLength(Result, 3);
Result[0] := TPersonRec.Create;
Result[1] := TPersonRec.Create;
Result[2] := TPersonRec.Create;
Result[0].Age := 20;
Result[1].Age := 30;
Result[2].Age := 40;
end;
function TTestActionResultController.GetPeople: TObjectList<TPerson>;
begin
Result := TPerson.GetList();
end;
function TTestActionResultController.GetPerson(id: Integer): IPerson;
begin
Result := TInterfacedPerson.Create('Daniele Teti', 20, 2010);
end;
function TTestActionResultController.GetPhoto: TStream;
begin
Context.Response.ContentType := TMVCMediaType.IMAGE_X_PNG;
Result := TFileStream.Create('sample.png', fmOpenRead or fmShareDenyNone);
end;
function TTestActionResultController.GetSingleRecord: TPersonRec;
begin
Result := TPersonRec.Create;
end;
function TTestActionResultController.GetStrDict: TMVCStringDictionary;
begin
Result := StrDict.Add('first_name','Daniele').Add('last_name','Teti');
end;
function TTestActionResultController.GetString: String;
begin
Result := 'Hello World';
end;
function TTestActionResultController.GetTComplexRecord: TComplexRecord;
begin
Result := TComplexRecord.Create;
end;
function TTestActionResultController.GetTSimpleRecord: TSimpleRecord;
begin
Result := TSimpleRecord.Create;
end;
function TTestActionResultController.GetObject(a, b: Integer): TSum;
begin
StatusCode := 201;
Context.Response.SetCustomHeader('X-CUSTOM-HEADER','CARBONARA');
Result := TSum.Create;
Result.Value := a + b;
end;
{ TComplexObject }
destructor TComplexObject.Destroy;
begin
FPerson.Free;
FPeople.Free;
inherited;
end;
procedure TComplexObject.SetPeople(const Value: TPeople);
begin
FPeople := Value;
end;
procedure TComplexObject.SetPerson(const Value: TPerson);
begin
FPerson := Value;
end;
{ TPersonRec }
class function TPersonRec.Create: TPersonRec;
begin
Result.FirstName := 'Daniele';
Result.LastName := 'Teti';
Result.Age := 99;
end;
end.

View File

@ -93,6 +93,7 @@ begin
.AddController(TTestServerControllerActionFilters)
.AddController(TTestPrivateServerControllerCustomAuth)
.AddController(TTestMultiPathController)
.AddController(TTestActionResultController)
.AddController(TTestJSONRPCController, '/jsonrpc')
.AddController(TTestJSONRPCControllerWithGet, '/jsonrpcwithget')
.AddController(TMVCActiveRecordController,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff