为什么 WebBroker-ISAPI-Module 中的文件访问只能在单独的线程中工作?

问题描述 投票:0回答:1

我正在使用 Delphi 11.1 和 WebBroker 开发我的第一个 ISAPI Web 模块,并且想要将日志写入文件系统。为了测试目的,我做了以下过程

TryWriteFile
,测试是否可以在
WebApplicationDirectory
中创建文件:

procedure WriteMyFile;
var
  fname: string;
  fs: TFileStream;
begin
  fname := TPath.Combine(WebApplicationDirectory, 'myfile.log');
  fs := TFileStream.Create(fname, fmCreate or fmOpenWrite or fmShareDenyNone);
  fs.Write([$54,$65,$73,$74,$0D,$0A], 6); { T e s t CR LF }
  fs.Free;
end;

现在,我尝试在 DefaultHandler 操作中调用

WriteMyFile
,但收到“访问被拒绝”异常:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  WriteMyFile;  //==> exception: access denied!
  Response.Content := 'no error!';
end;

当我从单独的线程调用

WriteMyFile
时,它可以工作。文件已正确创建:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  thr: TThread;
begin
  //WriteMyFile;  //==> exception: access denied!

  thr := TThread.CreateAnonymousThread(WriteMyFile); //works!
  thr.FreeOnTerminate := False;
  thr.Start;
  thr.WaitFor;
  thr.Free;
  Response.Content := 'no error!';
end;

所以我的问题是:为什么?和Windows文件夹权限有关系吗?如果是这样,那么在不同的线程中它们怎么会不同呢?

我的配置

IIS配置:

  1. ISAPI 限制设置为“允许未指定的 ISAPI 模块”
  2. 新的应用程序池
    MYPOOL
    • 没有托管代码
    • 启用32位(因为我的dll被编译为32位)
  3. 新网站“我的网站”
    • 物理路径
      C:\inetpub\wwwroot\MYPOOL\
      添加了“修改”权限
      IIS AppPool\MYPOOL
    • 处理程序映射:允许执行。

IIS 和 Delphi 11.1 Alexandria 都在我的 Windows 10 计算机上运行。

multithreading delphi isapi
1个回答
0
投票

无论您是从主线程还是从后台线程调用它,您的

WriteMyFile
过程的工作方式都没有区别。如果无法创建或写入现有文件,则会引发异常。

区别在于,当您从线程调用它时,引发的异常包含在线程内,并且不会传播到该线程外部的代码。

如果您想知道是否引发了异常,您可以检查线程的

FatalException
属性,如果已分配它,则它包含您可以检查的异常对象。

您可以在等待线程完成之后、释放线程之前或在线程

OnTerminate
事件处理程序中执行此操作。

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  thr: TThread;
begin
  thr := TThread.CreateAnonymousThread(WriteMyFile); 
  thr.FreeOnTerminate := False;
  thr.Start;
  thr.WaitFor;

  if thr.FatalException is Exception then
    Response.Content := Exception(thr.FatalException).Message
  else
    Response.Content := 'no error!';

  thr.Free;
end;
© www.soinside.com 2019 - 2024. All rights reserved.