Jump to content

Clément

Members
  • Content Count

    380
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by Clément

  1. Clément

    paste into watch list

    Just tested dragging with Delphi XE. It works! Always learning something new!
  2. Hi, I have a base Frame that I use to derive most of UI. Is there any problem if I use several interfaces in my child frames? For example : TMyCustomerFrame = Class( TBaseFrame, ISupportDataset, ISupportResize, ISupportSelection, ISupportCRUD, .. ) TMySupplierFrame = Class( TBaseFrame, ISupportORM, ISupportResize, ISupportExcel, ISupportDragDrop ) There's one Frame that implements 8 Interfaces. It Works! but ... Is there any limit (Design or concept)? Because so far using Interfaces is helping me a lot and coding got a lot simpler too. Happy New Year! Clément
  3. Yes. I'm redesigning to use their layout control. Most of my frames have standard VCL controls and some components of my own. Layout Control has an Import facility, but I can't use it right now. I have to reformat my frames to minimize rework. I tried importing some simple TFrames and it was easier to restart those from scratch. Some more complex frames got completely messed up. I'm experimenting with some reformatting/realigning to see if the Import result improves. Using their Layout Control is the way to go. Most of my visual problems are solved with it not to mention the component alignment is perfect.
  4. I tried to keep the post as short as possible, but I guess it won't be possible My English is not very technical (or good), I must use some examples to help me explain. The client side platform has "ready to use frames" with editors placed at design time. Some frames are easy to create at runtime, I won't talk about those. Others not so easy (Customer, Orders, Contract, Services, Billing etc). So I derive from the my baseFrame and drop the corresponding controls at Design time. This is almost the only thing I can do. My users have different monitor resolutions, some have some sight problems, and sometimes Windows cannot natively display some information in a way they can read it. So in my application offer them a way to choose their favorite fonts and font sizes (some of them uses Tahoma 20 bold for normal label/editors). For this reason, I must resize the form in order to fit them as "designed". There other factors too, like for example skins (Some customer want me to design skin to match their logo, company colors and stuff ). Anyway, this is strictly handled on the client side. But as any other application there are some restrictions applied to users ( or modules). Fields they can't edit, or fields they can't see. Those are the definitions coming from the server. At server side, there are some "hard validation rules", like for example StartDate must be Less or equal do EndDate. This kind is still hard coded and I guess this falls into your strong binding UI Definition. I try to keep those to a minimum. But there are some soft rules that applies depending on the user ( or module ). For example, I must check if document number is valid when editing data on Module A, but that same document is optional for Module B, so no validation is required. Yet again, this rule can apply to Customer A, but Customer B wants both modules A and B to validate the document number. The way I implemented it all I have to do assign the "IsRequired" for that particular document number field of module A and Module B accordingly to that customer needs. The server side platform (REST API with JSON) is handling complex requests (Definition + Data) only from my client side platform. Third party system integrate with my server platform using another authorization scheme and a different REST API route. No UI Presentation to deal with. So far, no customer requested complex browser features. The mobile side is pretty simple too. Data entry is not practical at all so the UI must be very well thought, objective, touchy, battery and processor friendly. The only thing the app receives is Data, no definition or maybe some soft rules definition to display some nice glyph to the user in the next few months. Mobiles get their own set of "forms". This was a way I found to deal with all this UI presentation logic. This is just an example to help illustrate. I'm sure there are better ways to manage it, that's why I like it here! Always learning a better way to implement things Clément
  5. Hi, It's a n-tier platform to help me build applications faster. I'm using TFrame to handle One thing : Visualization. For example: The ISupportAdjustToFrame will handle special form dimension. This mode doesn't allow the user to resize the form, the form is resized automatically to fit all editors and labels so they are displayed correctly (DPI, User fonts, etc). The ISupportDataset will handle data-aware editors with TDataset / TDatasource. The ISupportGrid will handle Grid, and in this case the form will be sized to a predefined value specified at design or runtime, and the user is allowed to resize up to a constraint limit. I like this solution because I can have a Frame that support Grid and Datasets, and another that support Grid and ORM. ( TFrameGridDataset = TBaseFrame+ISupportDataset + ISupportGrid and TFrameGridORM = TBaseFrame+ISupportORM + ISupportGrid respectivelly). The server side platform is holding part of the visual definition. The client request a "form design definition" and the response will contain the corresponding Frame name along with the visual components definition, all of them will be created at runtime. The client side platform has a few key "Form Containers" that will handle all those interface the frame depends on and display all those controls correctly. This way most definition will happen at server side. It's just a matter of picking the right Frame for the job Clément
  6. Yes, all references to the object are through interfaces. Really cool!
  7. Indeed Pack is the way to go. I guess I'm just biased by my current project.
  8. Have you considered using 2 TList<T> ? One for the actual data and the other as a " T object pool" Before adding a new Item in MainList, check the pool, if it's empty then return a newly created T or get the first (or last ) element. When you're done, move the object back to the Pool list. You will be able to avoid unnecessary allocating and freeing.
  9. Hi, I would check a few things... 1) Does vcl260.bpl exists in that folder? 2) Does it have a "valid size". If it is "zero" then you need to reinstall and may be your antivirus is getting in the way. Disable realtime protection and reinstall. 3) Your path might be corrupted (Not enough space for ex). 4) Somehow the 64bit version of the bpl is being loaded, and fails for obvious reasons. HTH, Clément
  10. Clément

    Debugger in 10.3.3 is useless :'(

    Here is a small example duplicating the exact same behavior of my main project procedure TForm1.FormCreate(Sender: TObject); begin fSomeConnector := TSomeConnectorCls.Create; caption := Format('Result= %d',[fSomeConnector.A1]); // Place a breakpoint here end; the IDE go to uSomeConnectorCls (line 22) : function TSomeConnectorCls.A1: Integer; begin Result := DoInvoke<Integer>('A1',[1,2]); // Press [F7] here end; Watch as the debugger completely ignores DoInvoke<T> and goes straight to DoBuildURI. Proceed with [F7] until DoBuildURI ends... and watch as the IDE goes back to the main form. The result is 11 so DoInvoke is called and executed to the last instruction! I wasn't able to duplicate the invalid entry point at the end of DoBuildURI when comment out of DoInvoke<T> though Undebuggable.zip
  11. Clément

    Debugger in 10.3.3 is useless :'(

    I don't think VM would work for me as I find myself running at least 2 instances of delphi. I don't think my machine can cope with host and VMs. Anyway, goodnews! I manage to isolate the problem in a small sample. Tonight I will do some more testing and I will attach the example. With that small sample, hopefully, you will be able to duplicate that behavior in your setup. I decided to keep 10.3.3. I will need less time modifying this code to something "debuggable" than making my project runs against Tokyo or Berlin. Most of my testing is automated, but some of those test are not compiling either under tokyo or berlin. I don't want to mess with my testing routines and with my already working code. So I will keep my current setup, and find a way around this "bug". Who's to say I would be in multi thread task without using sleep 😂
  12. Clément

    Debugger in 10.3.3 is useless :'(

    The code runs in Berlin and Tokyo ( I'm not crazy, yet! ). Anyway, with both 10.3.2 and 10.3.3 broken I will have to use Tokyo to debug and probably release the application by Dec 15. Under Tokyo the application is not compiling because there's some RTL diferences ( ex: enum exists in Rio but not in Tokyo). I'm fixing such glitches and as soon as I have a running system, I will work on that sample. I installed both 10.3.2 and 10.3.3 twice today, from scratch. Both developed NonDebuggable Agreement
  13. Clément

    Debugger in 10.3.3 is useless :'(

    I'm really worried. I completely removed 10.3 using the uninstaller. Using CCleaner I remove all leftover the uninstaller left. Using registry editor I removed all entries for Rad Studio 20.0 and all 1a.0 . Reinstalled 10.3.3 using the Webinstaller (All those trials are done with Webinstaller). Still no way to debug method with the following signature: function method<T>( const aMethodName : String; const aParams : Array of TValue) : T; What's next? Going ISO installer?
  14. Clément

    Debugger in 10.3.3 is useless :'(

    I completely remove 10.3 (Clean all registry et al) and reinstalled it. I deleted all dsk, dcus, .local but still, no way to debug the DoInvoke. Truly disappointed. I guess I'll have to hunt down all RAD Studio entries in my registry to be able to uninstall it properly. And one weekend is completely lost
  15. Clément

    Debugger in 10.3.3 is useless :'(

    Just installed 10.3.2 and the same debugger behavior is happening. 10.3.3 broke something. Well... tomorrow I will reinstall 10.3.3 from scratch
  16. Clément

    Debugger in 10.3.3 is useless :'(

    Indeed, The method function DoConvertWebAPIResponse<T>(aWebAPIResponse : TJSONValue ) : T; Also shows the same behavior. ( No blue dot, cannot place breakpoint, appears in the call stack and when accessed from the call stack shows a different part of the code. When I trace into some other routines that correctly displays the blue dots, the editor shows a completely wrong line. For example, when I hit [F7] to return to DoConvertWebAPIResponse<T> (which is inaccessible ) the debugger places the editor in middle of the class constructor and the Local Variable window displays the local variables from DoConvertWebAPIResponse. If I remove some of the private variable declaration like for example private fRTC : TRttiContext; fRttiType : TRttiType; fBaseRoute : String; The blue dot moves a little higher. I'm installing 10.3.2. Let's see if it's my Delphi installation that got corrupted and I'll have to do a clear installation, or if it works under 10.3.2 then I'll know for sure something is wrong with 10.3.3. In fact, it's very hard to duplicate. I'm not using IDE Fix pack. I don't think there's a 3rd party package problem/conflict. The 10.3.3 went well. No errors. All packages were loaded during the IDE startup. I compiled most of projects without any problem. I guess I got lucky to spot this issue on that particular project Clément
  17. Clément

    Debugger in 10.3.3 is useless :'(

    Well, I re-installed 10.3.3 and the problem persists. Going back to 10.3.2
  18. I used it by accident twice. UNDO is a life safer indeed. Never ever since. I guess we should build a "black list" of IDE feature we should avoid.
  19. Hi, I'm using TSslHttpAppSrv in a Delphi Rio project. I'm following the example and I manage to build my AppServer. Very cool! There are some points that I would like to understand better and maybe improve a little. I create a "TcoreWebServerThread" derived from TThread that creates an instance of TcoreWebServer. TcoreWebServer is a descendant of TSslHttpAppSrv. I hooked event_ClientConnect to OnClientConnect. procedure TcoreWebServer.event_ClientConnect(Sender, Client: TObject; Error: Word); var lRemoteClient : TcoreWebServerClientConnection; begin lRemoteClient := TcoreWebServerClientConnection(Client); lRemoteClient.WSessionCookie := 'dhsWeb_' + lRemoteClient.HostTag+ '_'+ Port; lRemoteClient.OnBgException := event_ClientBgException; fLogRequest[ lRemoteClient.WebLogIdx ].logFmt('Thread ID %d',[ThreadID]); end; This Connection is created in the context of coreServerThread. That same Thread will handle the Authorization, Permission and the URLHandler. It is too much for the server thread to handle, specially because Authorization (custom) and Permission will be checked against Database. Most of my TURLHandler descendants will also query a Database. Some will be slow ( Reports or Large data transfers). I must use a separate thread. And here's the problem. Where is the best place to create that thread? I haven't found a way to create the client connection in another thread. In the event_ClientConnect I would like "client" parameter to be in its own thread. This way all Authorization, Permission and TURLHandler execution would happen without blocking the main WebServer thread. Once I create the Client in a it's own thread context, I need to handle my Database Connection. I derived a class from TWebSessionData called ( TcoreWebServerWebSession ) : TcoreWebServerWebSession = Class( TWebSessionData ) private FLoginChallenge: String; FUserCode: String; FLastRequest: TDateTime; FRequestCount: Integer; FLogonTime: TDateTime; FIP: String; FSQLConnection: IcoreSQLConnection; public constructor Create( aOwner : TComponent ); override; property UserCode : String read FUserCode write FUserCode; property LogonTime : TDateTime read FLogonTime write FLogonTime; property RequestCount : Integer read FRequestCount write FRequestCount; property LastRequest : TDateTime read FLastRequest write FLastRequest; property IP : String read FIP write FIP; property LoginChallenge : String read FLoginChallenge write FLoginChallenge; property SQLConnection : IcoreSQLConnection read FSQLConnection; End; The property SQLConnection is an interface, and it's life time will be different from the WebSession's. I would like to return the SQLConnection back to its pool as soon as the user request is done. ( All the database connection pooling is already done! ). All the requests will return a JSON object. So, basically I need to place the ClientConnection on a separate thread that will Acquired a Database Connection from a pool and assign it to coreWebServerWEbSession.SQLConnection. This connection will be used to Authorize, Check permission and execute TURLHandler. Once Finished I would like to release it back to it's pool. No bad for a Sunday brainstorm TIA, Clément
  20. Clément

    Studying TSslHttpAppSrv

    Thanks for taking your time to answer! I'm still studying the best course of action. All client connections will receive a response very fast. For synchronous request, I want to return an answer with a maximum delay of 2s. For Asynchronous request the response will be very fast, just the time to spawn a thread ( as you saw in the example). The example is just a test, the final version will mostly look like: procedure TWSWebAPIHandler.Execute; var lJsPostedData : TJsonObject; lPath : String; begin inherited; if IsLogged then begin lJsPostedData := TJsonObject.ParseJSONValue( Client.PostedData ) as TJSONObject ; lPath := Client.Path; TWSWebServerAPIThread.Create( LPath, lJsPostedData); AnswerString('', '', '', '<HTML><BODY>WebAPI called - '+Client.Path+' </BODY></HTML>'); end else AnswerString('', '', '', '<HTML><BODY>Not logged </BODY></HTML>'); Finish; end; I thought I might need access to TURLHandler from within the thread. But that's not the case anymore. By the way, The user authentication is done very fast ( I'm already connecting to a database to get the credentials in the context of the TcoreWebServer). The performance is great. I need to polish some classes and interfaces to start the project. I will decorate my class definitions with attributes like [Operation(Sync)] or [Operation(Async)] to know if I need to spawn a thread or not in the API call layer. Thanks, Clément
  21. Clément

    Studying TSslHttpAppSrv

    Hi, I have two questions: 1) In my implementation I see that fUrlHandler.Client messages are processed by TCoreWebServer message pump. Would that be a problem? I could instead pass TURLHandler's FWndHandle, but still would have to PostMessage that would be processed in TCoreWebServer thread 2) Some database operation can take a few hours to complete. From the source code, TURLHandler is released after calling fUrlHandler.Finish. Would maintain a TUrhHandler instance live for a few hours be an issue? TIA, Clément
  22. Clément

    Studying TSslHttpAppSrv

    I found a way to get the result I want. I just hope it is the right way. I wrote a TUrlHandler descendant that spawn a thread. One of those parameters is the TUrlHandler instance. The code looks like this: procedure TWSWebAPIHandler.Execute; var lJsPostedData : TJsonObject; lPath : String; begin inherited; if IsLogged then begin lJsPostedData := TJsonObject.ParseJSONValue( Client.PostedData ) as TJSONObject ; lPath := Client.Path; TWSWebServerAPIThread.Create( LPath, lJsPostedData, Self ); // AnswerString('', '', '', '<HTML><BODY>WebAPI called - '+Client.Path+' </BODY></HTML>'); end; // Finish; end; As you can see I commented the answer string and the finish. They are in the Thread implementation: constructor TWSWebServerAPIThread.Create(const aPath: String; aPostedData: TJsonObject; aURLHandler: TcoreWebServerHandler); begin FreeOnTerminate := True; fPostedData := aPostedData; fPath := aPath; fURLHandler := aURLHandler; inherited create(False); end; procedure TWSWebServerAPIThread.Execute; begin inherited; Sleep(9000); fURLHandler.AnswerString('','','','<HTML><BODY>In a thread for '+fPath+' with '+fPostedData.ToString+'</BODY></HTML>'); fURLHandler.Finish; end; The Sleep(9000) is there just to simulate a long database operation. I have tested the calling from 3 different REST Client and every response came at 9s as expected. (Without that thread, the requests will return at 9s, 12s and 18s. Exactly what I'm trying to avoid). This codes uses an instance of TUrlHandler because it seems to me that every request will get an instance of the corresponding TURLHandler. Is it thread safe to call it that way? TIA, Clément
  23. Clément

    Studying TSslHttpAppSrv

    Sure. My concern is the response to the request. I don't want the user to wait longer than (s)he needs to. I will divide my request in Sync and Async calls. Sync calls should be very fast and it might work without a database thread (I will do some test as soon as I manage to create a thread for the client connection). Async calls on the other hand might take several hours.
  24. Clément

    Studying TSslHttpAppSrv

    This server will run as a Windows Service. It may be a bad habit, but I don't like to share the service thread with my applications. I will have a look. I need SocketThrdServer features in TsslHttpAppSrv. It makes no sense going back. This is the tricky part. Some requests will be synchronous and some asynchronous. Synchronous request will have the database in the same thread as the client connection. This is the fast kind of request. Usually a result is expected from 1ms to less than 2s (in my case). The asynchronous request will release the client connection as soon as possible. It will trigger a process that sill handle longer requests and alert the users once it's completed.
  25. Clément

    Interesting article about dying languages

    This is the kind of article that falls in the wrong hands and I always hear: "I know more people that talk Latin than delphi programmers". "What? A new project in Delphi? Are you nuts?" Hopefully Delphi Community edition will help re-popularize (is that even a word?) it. The fact is that most script base language programmed by young developers do REST calls (or something like), so as long as you GET, DELETE, POST and PUT in fancy syntax you are in a modern langue!
×