Skip to content

relative paths in WebStencilsDemo as ISAPI module #6

@fritsr

Description

@fritsr

Hi Antonio,

I want to deploy a Webstencils website as an ISAPI module. A standalone console app is not always the best solution. And a CGI app will 'forget' the sessions in between calls.

As an exercise I took your example and changed it into an ISAPI module. Doing so I found (and solved) a few problems.
My goal is to just replace the .dpr file without making any changes in any other file. I would like to be able to use the next version of the WebstencilsDemo without changes ;)
I do get the example working as an ISAPI module, but I needed to make some changes in your code.
I want to suggest some changes in your example.

relative paths
The main problem is about relative paths.
When you have the page
http://localhost:8081/templates
I have a URL with a longer path with the name of the .dll:
https://www.mydomain.nl/WebStencilsDemo/WebStencilsDemo_13_isapi.dll/templates
A link to the relative path /login works in your example. In the ISAPI module I get a link to
https://www.mydomain.nl/login
while I want a link to
https://www.mydomain.nl/WebStencilsDemo/WebStencilsDemo_13_isapi.dll/login

A few suggestions
1. <a href="@env.resource/customers/add"
in resources\html\customers\index.html (@env.resource is missing)
2. <form method="get" action="@env.resource/customers">
in resources\html\partials\customers\searchForm.html (@env.resource is missing)
3. <a href="@env.resource/@page.request_path"
in resources\html\partials\customers\searchForm.html (@env.resource is missing)
4. A change in Modules.Main solves a lot of problems:
else if APropName = 'resource' then AValue := request.InternalScriptName
In your example this is an empty string, for me it is /WebStencilsDemo/WebStencilsDemo_13_isapi.dll

redirect
There are (at least) three places where a redirect to relative paths occurs. In your code this can be solved in the AfterDisPatch event, like this:

procedure TMainWebModule.WebModuleAfterDispatch(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  // Message clearing - only when not redirecting
  var IsRedirect := (Response.StatusCode >= 300) and (Response.StatusCode < 400);
  if not (IsRedirect) and Assigned(Request.Session) then
    TMessageManager.ClearMessages(Request.Session);
  if IsRedirect and (Response.location[1]='/')
  then Response.location := Response.HTTPRequest.ScriptName + Response.location;
end;

Both TMyWebFormsAuthenticator and TMyWebAuthorizer do redirects. Unfortunately in Web.HTTPApp this redirect is done with a call to SendRedirect. With a call to SendRedirect there is no WebModuleAfterDispatch event. So I cannot change the location there.
I don't know what would be the best solution. Maybe a kind of BaseUrl you can set in the properties? Or some code like above in the WebModuleAfterDispatch ? An AfterRedirect event ?

For now I have been able to solve this with an override of the Redirect function in the inherited TMyWebFormsAuthenticator.

function TMyWebFormsAuthenticator.Redirect(Request: TWebRequest;
  Response: TWebResponse; Action: TWebAuthenticatorAction): string;
begin
  result:=inherited;
  if result[1]='/'
  then result := Response.HTTPRequest.ScriptName + result;
end;

And the same for TMyWebAuthorizer.

I don't like this solution, because you have to change the properties of WebFormsAuthenticator in code, like this:

  WebFormsAuthenticator.Free;
  WebFormsAuthenticator := TMyWebFormsAuthenticator.Create(Self);
  WebFormsAuthenticator.LoginURL:='/login';
  WebFormsAuthenticator.LogoutURL:='/logout';
  WebFormsAuthenticator.HomeURL:='/';
  WebFormsAuthenticator.OnAuthenticate:=WebFormsAuthenticatorAuthenticate;

Do you see a better solution ?

BinaryPath
In an ISAPI dll Paramstr(0) gives the path to the IIS webserver. I want to have the path to the .dll.
Fortunately we can do a call to the function GetModuleName(hinstance).
On the server this path can start with '\\?\' to denote a possibly long path.

So this is my code in TMainWebModule.InitRequiredData:

BinaryPath := TPath.GetDirectoryName(GetModuleName(hinstance));
 if BinaryPath.StartsWith('\\?\')
 then BinaryPath:=BinaryPath.Substring(4); //remove \\?\

A small improvement
I have a couple of versions of your example. I want to see directly witch version I'm looking at. So I gave them a slightly different app_name. I want to see this in the title. This is so simple in WebStencils !
<title>@env.app_name</title> in resources\html\layouts\baseLayout.html

Thanks,
Frits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions