You are not logged in.
Hi,
What if mORMot 2.0 includes an IoC Framework for generic services (Not only mORMot services)(ex. IEmailSender <-> TFastEmailSender)?
Delphi has some IoC Frameworks on the network but FPC hasn't!
What do you think about it?
Thanks for this nice implementation for Python!
Hi,
I am beginning to look at it now and I really liked this very good framework, so I am considering to use it in my project.
But I have some objects that I want to persist in a database whose classes have generic TObjectList<T> properties set in then.
So, would it be possible to use these generic properties with mormot or am I forced to use a simple TObjectList?
Just to show what I mean, look at this little example:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
TExampleClass = class(TSQLRecord);
TMySQLRecordClass = class(TSQLRecord)
private
FMYObjList: TObjectList<TExampleClass>;
procedure SetMYObjList(const Value: TObjectList<TExampleClass>);published
property MYObjList : TObjectList<TExampleClass> read FMYObjList write SetMYObjList;
end;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////I know mormot have compability with many prior delphi versions, But I think it would be great if we could use a generic like this, it would make it easier to implement on my project;
mORMot and DDD changed my mind. Now, I have two data models, one for database aggregation with simple types (Arrays and records) and another model for frontend representation and logic (ObjectList, Methods). It's better to separate models than have only one model for logic and aggregation. Correct me Arnaud if I am wrong.
You don't need to run the program with admin rights.
If you register the URI from command line with admin rights, just once (as a regular IIS URI), you can then run the service with normal rights.
Azure AppService is a self managed enviorment and can't setup an HTTPApi.sys server at all.
Perhaps 256 may be slower than 32, in practice, if you have a proxy, and only 4 cores.
Only you could know which parameter is the best, by trying on real HW and SW.
Yeah this is the best way to test it. We will put this line on server Constructor (System.CPUCount * 8 on threadpool size value).
Thanks for your advices.
So you are using the http.sys-based server?
The thread pool default parameter should be good enough for your purpose, since 32 is much higher than your server core count, and most of the time will be spent in the Windows kernel, in the http.sys communication process.
No, we are using bare TCP THTTPServer because Azure AppServices applications can't use administrator called apis... But we have an IIS proxy (ARR) above. Our constructor is called with 256 value on threadpool parameter.
Hi,
First of all, I want to congratulate Synopse team, they are doing a great task! mORMot is one of the big things that changed my mind to not left Pascal. Thanks!
We have made an online (image-resizer & compression) HTTPServer application in Delphi Pascal that uses Synopse low level SynCRTSock.THttpServer. This application is running very well at Azure under AppService with 5 instances(machines quad core). Has replaced a slow .NET Core application based on kestrel running at 10 instances. Our service has more than 30 milions of request/day under a Microsoft ARR and Akamai CDN.
Some advice to improve/optimize SynCRTSock.THttpServer ? If can be improved more. Server constructor param ThreadPool is useful?
This is a simple solution to deploy mORMot server on IIS and let it control ip restrictions, https certificates, logs, etc...
Thank you very much! Very nice way to deploy custom .exe WebServers using IIS as frontend web server.
I'm using CodeTyphon
Avoid Codetyphon. Try to use NewPascal instead
Currently I'm using LinuxMint and Ubuntu + Debian. With NewPascal of course
Yes, It's compatible! But you will need to use FPC to cross-compile the code. Delphi ARM compiler from 10.2 Enterpri$e Edition is not compatible.
FPC is the way to go I am migrating my projects to it. Compiler is getting strong and native cross-platform cross-architecture support. Some day in the future FPC will be the natural replacement to Delphi. IMHO.
Feedback is welcome: I didn't test it on NextGen/iOS/Android platforms.
I'm currently developing/testing it for a Firemonkey Android client. I will back with updates.
I've added TSQLRest.RetrieveList<T> to the cross-platform clients.
See https://synopse.info/fossil/info/1bbe25b1c6
Great! Thank you very much!
I will test it and make a pull request to your GIT repo.
Hi,
Would be nice and very useful to have this method on cross.
function TSQLRest.AddOrUpdate(Value: TSQLRecord; ForceID: boolean): TID;
begin
if (self=nil) or (Value=nil) then begin
result := 0;
exit;
end;
if ForceID or (Value.fID=0) then begin
result := Add(Value,true,ForceID);
if (result<>0) or (Value.fID=0) then
exit;
end;
if Update(Value) then
result := Value.fID else
result := 0;
end;
I think the code will work as is.
I would rather add something like in the main mORMot.pas unit.
That is, properly using generics for the overloaded version - something like:
{$ifdef ISDELPHI2010} // Delphi 2009 generics support is buggy :( function RetrieveList<T: TSQLRecord>(const FieldNames, SQLWhere: string; const BoundsSQLWhere: array of const): TObjectList<T>; overload; {$ifdef HASINLINE}inline;{$endif} {$endif}
Your version would be confusing for the compiler.
Yes it's much better than mine.
Hi,
To improve the compatibility with original mORMot, it would be great to implement generics.
For example :
function RetrieveList(Table: TSQLRecordClass; const FieldNames,
SQLWhere: string; const BoundsSQLWhere: array of const): TObjectList;
For this :
{$IFDEF NEXTGEN}
function RetrieveList(Table: TSQLRecordClass; const FieldNames,
SQLWhere: string; const BoundsSQLWhere: array of const): TObjectList<T>;
{$ELSE}
function RetrieveList(Table: TSQLRecordClass; const FieldNames,
SQLWhere: string; const BoundsSQLWhere: array of const): TObjectList;
{$ENDIF}
Sorry but this is not the way to use the ORM, avoid complex queries like JOIN and more.
Thanks for your help,
But:
- when the 'GetBooks' fired?
- What the purpose of the 'TArrayHelper'?I still didn't manage to get all books for specific student, for example: http://localhost:8080/service/students/10/books
GetBooks is fired when you need to get the books of the student at runtime. ( StudentInstance.GetBooks ).
The purpose of TArrayHelper is a simple helper of arrays using Synopse awesome dynamic array wrapper.
Hi mhmda,
This is my humilde aproach :
TRecordReferenceArray = array of TID;
TArrayHelper = class
public
class function IsMine(aReference: TID;
var aReferenceArray: TRecordReferenceArray): Boolean;
class procedure DeleteRecord(aReference: TID;
var aReferenceArray: TRecordReferenceArray);
class procedure AddRecord(aReference: TID;
var aReferenceArray: TRecordReferenceArray);
end;
TBook = class(TSQLRecord)
end;
TStudent = class(TSQLRecord)
private
fbooks : TRecordReferenceArray;
public
function GetBooks(RestClient : TSQLRest) : TObjectList<TBook>;
procedure AddBook(ID : TID);
published
property Books : TRecordReferenceArray read FBooks;
end;
class procedure TArrayHelper.AddRecord(aReference: TID;
var aReferenceArray: TRecordReferenceArray);
var
dynarray: TDynArray;
begin
dynarray.Init(TypeInfo(TRecordReferenceArray), aReferenceArray);
dynarray.FindAndAddIfNotExisting(aReference);
end;
class procedure TArrayHelper.DeleteRecord(aReference: TID;
var aReferenceArray: TRecordReferenceArray);
var
dynarray: TDynArray;
begin
dynarray.Init(TypeInfo(TRecordReferenceArray), aReferenceArray);
dynarray.Delete(dynarray.IndexOf(aReference));
end;
class function TArrayHelper.IsMine(aReference: TID;
var aReferenceArray: TRecordReferenceArray): Boolean;
var
dynarray: TDynArray;
begin
dynarray.Init(TypeInfo(TRecordReferenceArray), aReferenceArray);
Result := dynarray.IndexOf(aReference) <> -1;
end;
procedure TStudent.AddBook(ID: TID);
begin
TArrayHelper.AddRecord(ID, fbooks);
end;
function TStudent.GetBooks(RestClient: TSQLRest): TObjectList<TBook>;
begin
Result := (RestClient.RetrieveList<TBook>('ID in (?)', [Self.fbooks]));
end;
As Arnaud said, it's better to store the relationship ID's in a dynamic array. It's very easy to implement and respects the principles of CRUD.
Thanks Arnaud I appreciate your fast response
I will use another pattern/method to populate non persistent values.
Hi,
It would be a nice idea to put a reference of client TSQLRest inside a TSQLRecord because lazy loading of public properties on runtime.
Imagine the next scenario :
TMe = class(TSQLRecord)
private
ffriendcount : Integer;
frestinstance : TSQLRest;
public
property FriendCount : Integer read ffriendcount;
function FillOne: boolean;
published
property Name : RawUTF8 read fname write fname;
end;
function TMe.FillOne : Boolean
begin
result := Inherited;
if result then frestinstance.OneFieldValue(TFriends, 'COUNT(*)', 'ISMyFriend=?', [], [True], ffriendcount);
end;
When call Constructor (CreateAndFillPrepare) keep the SQLRest instance.
What do you think?
Hi,
You need to study all samples embedded and learn how all layers of mORMot works. Your project is one of the easiest projects to achieve, but we can't help you to write all the code for it.
You need server side (the most important thing) a REST Server with persistence SQLite3 for example (you can implement TSQLRestServerDB with a TSQLHttpServer). And on the client side you will need a consumer TSQLHttpClient.
Thanks to mORMot SOA + REST + JSON you can consume like a regular HTTP REST standards with an HTTPClient.
Useful after TRUNCATE or masive delete of pages, VACUMM works well to free database pages.
Amen,
Don't waste your time with bloated Embarca$$$ro Linux Compiler. Use FPC instead.
I made this working using mORMot HTTPApiSockets fork without problems.
If you are accessing the server via HTTP client, you can place an HTTP proxy in front your backend servers and scale the ORM horizontally.
More documentation here : https://github.com/projectkudu/kudu/wik … pp-sandbox
You can do this with an HTTPClient. Every HTTP proxyes do this things.
As an alternative, the executable may check the environment variable HTTP_PLATFORM_PORT, and use it instead of paramstr(1).
Not at all. HTTP_PLATFORM_PORT is not a enviroment variable... I tried to do and nothing found.
PS D:\home> echo %HTTP_PLATFORM_PORT%
MS is hiding things and wants you code in .NET and popular languajes like JS with Node. But no... I continue to do things natively with C++ and Object Pascal.
Great!
I guess you are using powershell access to the instance.
You can access via powershell or HTTP panel.
But IIRC such Azure instances don't have local persistence: whatever you wrote locally may disappear if the VM manager moves your virtual instance to another hardware...
So you should use remote storage for any persistence...
Yes, no local persistence. But I don't need persistence at all... I am doing a (Delphi/Assembler Mega optimized) HTTP Image Converter and I want to deploy it to Azure with AppServices (not VM)
VM's are more expensive, hard to scale and deploy.
Worth adding to the framework documentation, once proven
Of course! this is a big deal for Azure DevOps!
Did!
We are using autoscalable Azure App Services (not VM's).
What do you need to know about this?
- You have an sandbox enviorment with an IIS acting like a proxy. ex. x.x.x.x:80 -> 127.0.0.1:25000
- You do not control any machine or VM.
- You can control vertical and horizontal scalability.
- You can't do administrative actions on your server.
- Every console out on your program will be flushed on log file.
- Your application needs to accept parameters (paramstr[1] -> TCP port forwarded by IIS)
- You need to bind server on 127.0.0.1 with paramstr[1]
(Only works with non-based HTTPApiServer because you have an IIS-Proxy above)
Here are the instructions :
- Compile your custom .exe HTTP server
- Upload exe to /site/wwwroot folder
- Generate a webconfig file at /site/wwwroot folder with the next content :
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<remove name="httpplatformhandler" />
<add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\YOUREXE.log" startupTimeLimit="20" processPath="%HOME%\site\wwwroot\YOUR EXE" arguments="%HTTP_PLATFORM_PORT%"/>
</system.webServer>
</configuration>
- Restart azure AppService instance
- Open a HTTP/s request to your service
- Voilà
You two are wrong... I will upload the instructions when I finished the deployment. But I did it.
How can be faster binary compiled with Delphi 7 than 10.1?
@turrican, thanks for getting back to this thread and sharing the info with us. And yes, good to hear that, SQLite3 never failed us:)
No problem! You are welcome!
Hi!
Currently we are moving to Azure and we found Azure AppServices. This kind of SaaS services can manage backend-webapplications made with .NET, PHP, NodeJS and JAVA. I'm curious if mORMot backend servers can be deployed on this platform. We are going to try the deployment.
Somebody deployed code in this platform?
Maybe there are too much index on your sqlite table ? 7GB table may counts 2~3 billion rows , update is not easy on any RDBMS. I'm curious whether your MSSQL faster now ? @turrican
Finally was the Hard Disk Volume perfomance... very fast with another server. I don't move from SQLite3 engine
Obviously it is not a replacement... but a way to share realtime experience and thoughts about this framework. For example know better the community
Hi,
I use Telegram to comunicate with the world and I take the lead and created a mORMot group to speak about this awesome framework.
You are welcome to join here : https://t.me/joinchat/AAAAAAyXgOZHC6irJH3XGg
Thanks!
No problem mohsenti
What is your mORMot goal? What do you need to achieve? mORMot's JSON Serializer is very easy to understand (i think) what is your problem with serializer? I can help you if you want.
Hi mohsenti,
For me mORMot is a lot of fresh air for Delphi and FreePascal. mORMot is one of best projects/frameworks I seen. POO, SOA... better than Embarcadero$$$IDERA will. A lot of Examples and well defined. Good forum community and a awesome but busy project lead (even he has time to respond posts )
I haven't no complaints with this framework... the source code is well commented and has a extensive documentation... You will reach everything you want with mORMot and you can extend it if you need.
Don't give up... continue learning, try again my friend.
Hi,
Actually I replaced (IIS 8.5 and .NET Framework 4.6 C# MVC based Application) with (Object Pascal mORMot framework using THttpApiServer). All features are working outstanding and performing better than .NET in most cases.
I want to implement multimedia streaming to client, so I need to write on headers directly before HTTP response. There is some way to do this?
Ok it's in fossil branch... Can you push this branch on GitHub Repo?
There is some chance to merge with main branch? your implementation is awesome.
Where is this Unit? I'm very interested to use your implementation.
Ok... I think the problem comes with the next situation :
- Firefox and Chrome passes Sec-WebSocket-Extensions:"permessage-deflate" header to server and server do the next thing :
extin := ClientSock.HeaderValue('Sec-WebSocket-Extensions');
if extin<>'' then begin
CSVToRawUTF8DynArray(pointer(extin),extins,';',true);
if not prot.ProcessHandshake(extins,extout,nil) then begin
prot.Free;
result := STATUS_UNAUTHORIZED;
exit;
end;
end;
Server aborts negotiation if ClientSock.HeaderValue('Sec-WebSocket-Extensions')
function TWebSocketProtocol.ProcessHandshake(const ExtIn: TRawUTF8DynArray; out ExtOut: RawUTF8;
ErrorMsg: PRawUTF8): boolean;
begin
result := false; // abort negotiation in case of any extension
end;
Override the ProcessHandshake method with Result := true;
So I don't know why Arnaud did this implementation. He will explain better than me.
Problem comes this way at SynBidirSock.pas
prot.fRemoteIP := ClientSock.RemoteIP;
prot.fRemoteLocalhost := ClientSock.RemoteIP='127.0.0.1';
extin := ClientSock.HeaderValue('Sec-WebSocket-Extensions');
if extin<>'' then begin
CSVToRawUTF8DynArray(pointer(extin),extins,';',true);
if not prot.ProcessHandshake(extins,extout,nil) then begin
prot.Free;
result := STATUS_UNAUTHORIZED;
exit;
end;
end;
I'm going to compare IExplorer requests with Chrome and Firefox.
Thanks rclaros,
Interesting... I'm going to check why latest builds don't work with Chrome and Firefox browsers.
Solved by this way : http://pastebin.com/UrMHSneL
Another question... Chrome and Firefox returns a 401 and 400 when try to access : http://localhost:8888/whatever/
IExplorer goes well.
Thanks AB.
BTW, I am testing Project31SimpleEchoServer with supplied Project31SimpleEchoServer.html client. This works ok.
There is some way to find all connected sockets in the server and send information to?