Delphi: 如何从 idHTTPServer.OnCommandGet 方法在主线程中执行过程

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

我必须在我们的应用程序中创建一个嵌入式 HTTP 服务器。 进程间通信必须创建这个,因为对方只能调用WebService。

我们不需要一次处理更多请求,但我必须从主线程使用库和数据库连接。

Delphi版本是 Seattle,Indy 版本是 10(内部)。

据我所知,IdHTTPServer 像以前一样使用线程进行连接。 但是新的事件处理程序不直接传递 Thread - 所以我不能像 N 年前那样调用 TThread.Synchronize。 而且我没有找到任何获取线程的方法。

我在某处读到 TIdSync 或 TIdNotify 类 可以帮助我。我找不到任何完整的示例来了解如何操作。

看到这个简单的代码。在主线程中完成我的工作是否足够?

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;

还是我做错了什么?

感谢您的帮助!

dd

有一种方法可以访问 TIdContext 背后的底层 TThread - 将 TIdContext.Yarn 属性 类型转换为 TIdYarnOfThread 然后访问其Thread 属性, 如:

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;

但是,在你的情况下你实际上并不需要它,因为 TThread.Synchronize() (and TThread.Queue()) 有 class 方法重载,所以你不需要 TThread 对象来调用它,例如:

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

TIdSync(和TIdNotify)确实可以代替使用,你所拥有的是一个好的开始,它只需要再充实一点,以便访问你的FURIFResult 变量也是同步的,以防您需要一次处理多个客户端连接,因此需要避免并发访问变量,例如:

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;

也就是说,TIdSync(和 TIdNotify)已被弃用,取而代之的是支持 anonymous proceduresTThreadclass 方法重载,例如:

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;

或者:

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;