delphiindyindy10delphi-11-alexandria

How to use TIdHTTPServer with visual components?


I have an app that uses TIdHTTPServer to run a simple HTTP server on port 80. I'm using the OnCommandGet event to get commands and return data using TClientDataSet.

It works, but the problem is, this same app has visual components attached to the TClientDataSet, like TDBGrid.

And what is happening is, when OnCommandGet changes TClientDataSet.CommandText, the TDBGrid needs to be updated and then weird things start to happen: the TDBGrid starts to have glitches, the Form itself starts to behave strangely. After this happens, the only fix is to restart the application.

I know that probably this is because some thread is messing with visual components and I know I should avoid this by synchronizing the thread, but I don't know how to do this using TIdHTTPServer.

Any help would be very appreciated, I'm having to restart my app several times during the day.


Solution

  • I know that probably this is because some thread is messing with visual components

    Correct. TIdHTTPServer is a multi-threaded component, its OnCommand... events are fired in worker threads, so you must synchronize with the main UI thread when touching UI components.

    I know I should avoid this by synchronizing the thread, but I don't know how to do this using TIdHTTPServer.

    You synchronize with the main UI thread like with any other worker thread - by using the TThread.Synchronize() or TThread.Queue() method, or Indy's TIdSync or TIdNotify class. For example:

    procedure TMyForm.IdHTTPServer1CommandGet(AContext: TIdContext;
      ARequeestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
    begin
      ...
      TThread.Synchonize(nil, // or TThread.Queue()...
        procedure
        begin
          ...
          ClientDataSet1.CommandText := ...;
          ...
        end
      );
      ...
    end;
    

    The alternative is to simply not touch the TClientDataSet in the OnCommandGet event at all. Give the thread its own dedicated connection to the database and use local components to query/update the data. Have the main thread use its own database connection when hooking up the TDGBrid.