1

I was testing a simple Delphi ISAPI application in order to see how it internally works when IIS receive multiple/parallel requests.

I know IIS can span multiple "IIS Worker Process" probably to do just that, but, as per application-pool settings, the default is 1 single "IIS Worker Process".

I know IIS (in each single "IIS Worker Process") can create multiple TWebModules instances in separate threads in order to handle concurrent / parallel requests.

Is there a way to identify each "currently running" TWebModule? Maybe via some "reference" or ID each TWebModule has?

My current project file:

library TestIsapiProject;

uses
  Winapi.Windows,
  Winapi.ActiveX,
  System.SysUtils,
  System.Win.ComObj,
  Web.WebBroker,
  Web.Win.ISAPIApp,
  Web.Win.ISAPIThreadPool,
  TestIsapiMainWebModuleUnit in 'TestIsapiMainWebModuleUnit.pas' {WebModule1: TWebModule};

exports
  GetExtensionVersion,
  HttpExtensionProc,
  TerminateExtension;

begin
  ReportMemoryLeaksOnShutdown := true;
  CoInitFlags := COINIT_MULTITHREADED;
  IsMultiThread := true; // already present in ...
  TISAPIApplication(Application).OnTerminate := TerminateLast; // very last finalize
  Application.MaxConnections := 2; // connectionsactivemax 32 by default
  NumberOfThreads := Application.MaxConnections;
  Application.CacheConnections := true; //not IsDebuggerPresent; // default is true, false will create/destroy isapidll with each request, do not use it in production
  Application.Initialize;
  Application.WebModuleClass := WebModuleClass;
  Application.Run;
end.

and web-module:

unit TestIsapiMainWebModuleUnit;

interface

uses
    System.SysUtils
  , System.Classes
  , Web.HTTPApp
  ;

type
  TWebModule1 = class(TWebModule)
    procedure WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModuleClass: TComponentClass = TWebModule1;

implementation

uses
    Winapi.Windows
  , Web.Win.ISAPIHTTP
  , Web.WebBroker
  ;

function GetProcessID: cardinal; register; assembler;
{$IFDEF 32BIT}
asm
  mov eax, FS:[$20]
end;
{$ELSE}
begin
  Result := Winapi.Windows.GetCurrentProcessId;
end;
{$ENDIF}

function GetThreadId: cardinal; register; assembler;
{$IFDEF 32BIT}
asm
  mov eax, FS:[$24]
end;
{$ELSE}
begin
  Result := Winapi.Windows.GetCurrentThreadID;
end;
{$ENDIF}

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content :=
                 '<html>'
  + sLineBreak + '<head><title>Web Server Application</title></head>'
  + sLineBreak + '<body>'
  + sLineBreak + '<pre>'
  + sLineBreak + 'Test Isapi Web Server Application'
  + sLineBreak + 'datetime            : ' + DateTimeToStr(Now)
  + sLineBreak + 'pid                 : ' + GetProcessID.ToString
  + sLineBreak + 'tid                 : ' + GetThreadId.ToString
  + sLineBreak + 'requestconnid       : ' + (Request as TISAPIRequest).Ecb^.ConnId.ToString
  + sLineBreak + 'connection/webmodule: ' + '???'
  + sLineBreak + 'maxconnections      : ' + Application.MaxConnections.ToString
  + sLineBreak + 'activeconnections   : ' + Application.ActiveCount.ToString
  + sLineBreak + 'inactiveconnections : ' + Application.InActiveCount.ToString
  + sLineBreak + 'cachedconnections   : ' + Ord(Application.CacheConnections).ToString
  + sLineBreak + '<pre>'
  + sLineBreak + '</body>'
  + sLineBreak + '</html>';
end;

end.
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Why do you want to know that? – Olivier Jan 04 '21 at 08:45
  • I would like to write each webmodule's activity in its own log file, so I tought it will be ok to use this information for the filename. – user14889477 Jan 04 '21 at 21:38
  • A TWebModule is only identified by it’s own object pointer and nothing else. If you need some other identification you will need some autoinc Id property. But it’s not that each TWebModule will be used by the same thread each time. But if you want to log stuff, it’s better to create a thread safe global logentry collector, which writes the log entries to a single file. On the other hand you can just try to create/open logfile1 and when it fails, open/create logfile2, until you get to one you can create/open. – R. Hoek Jan 04 '21 at 22:13

0 Answers0