简体   繁体   中英

Delphi: how to execute procedure in main thread from idHTTPServer.OnCommandGet method

I have to create an embedded HTTP server in our application. This must be created for interprocess communication, because the other side can call only WebService.

We don't need to process more requests at once, but I must use the libraries and DB connection from the main thread.

The Delphi version is Seattle, the Indy version is 10 (internal).

As I know the IdHTTPServer uses threads for connections - as formerly. But the new event handler don't pass the Thread directly - so I can't call TThread.Synchronize as N years before. And I didn't find any way to get the thread.

Somewhere I've read that TIdSync or TIdNotify classes could help me. I can't find any complete example to see how.

See this simple code. Is it enough to do my work in main thread?

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
    AResponseInfo: TIdHTTPResponseInfo);
begin
    FURI := ARequestInfo.URI; // Store the URI for main thread access
    FResult := '';
    TIdSync.SynchronizeMethod(Self.ProcessIt); // Call sync to process in VCL thread
    AResponseInfo.ContentText := FResult; // This variable contains the result
end;

Or I do something wrong?

Thank you for the help!

dd

There is a way to get access to the underlying TThread behind a TIdContext - typecast the TIdContext.Yarn property to TIdYarnOfThread and then access its Thread property, eg:

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  Thread: TThread;
begin
  Thread := (AContext.Yarn as TIdYarnOfThread).Thread;
  FURI := ARequestInfo.URI;
  FResult := '';
  Thread.Synchronize(ProcessIt);
  AResponseInfo.ContentText := FResult;
end;

But, you don't actually need that in your situation, because TThread.Synchronize() (and TThread.Queue() ) has class method overloads, so you don't need a TThread object to call it, eg:

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  FURI := ARequestInfo.URI;
  FResult := '';
  TThread.Synchronize(nil, ProcessIt);
  AResponseInfo.ContentText := FResult;
end;

TIdSync (and TIdNotify ) can indeed be used instead, and what you have is a good start for that, it just needs to be fleshed out a little more so that access to your FURI and FResult variables is synchronized as well, in case you ever need to handle more than 1 client connection at a time and thus would need to avoid concurrent access to the variables, eg:

type
  TIdProcessItSync = class(TIdSync)
    URI: string;
    Content: string;
  protected
    procedure DoSynchronize; override;
  end;

procedure TIdProcessItSync.DoSynchronize;
begin
  Content := Form5.ProcessIt(URI);
end;

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  Sync: TIdProcessItSync;
begin
  Sync := TIdProcessItSync.Create;
  try
    Sync.URI := ARequestInfo.URI;
    Sync.Synchronize;
    AResponseInfo.ContentText := Sync.Content;
  finally
    Sync.Free;
  end;
end;

That being said, TIdSync (and TIdNotify ) is deprecated in favor of TThread 's class method overloads that support anonymous procedures , eg:

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  URI, Content: String;
begin
  URI := ARequestInfo.URI;
  TThread.Synchronize(nil, 
    procedure
    begin
      Content := ProcessIt(URI);
    end
  );
  AResponseInfo.ContentText := Content;
end;

Alternatively:

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  TThread.Synchronize(nil, 
    procedure
    begin
      AResponseInfo.ContentText := ProcessIt(ARequestInfo.URI);
    end
  );
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM