1 Commits

Author SHA1 Message Date
justin d9b2499690 Auto-install .NET 8 runtimes if missing
A fresh Windows Server install has neither ASP.NET Core 8 nor .NET
Desktop 8, so the Service refuses to start and the GUI fails to
launch — the symptoms link to aka.ms/dotnet-core-applaunch but it's
not obvious from the GUI itself what's wrong.

Setup now:
- Detects each runtime by looking for an 8.x folder under
  %ProgramFiles%\dotnet\shared\Microsoft.{AspNetCore,WindowsDesktop}.App
- Uses Inno Setup's built-in TDownloadWizardPage to fetch any missing
  runtime from the aka.ms redirect and runs `/install /quiet /norestart`
- Treats Microsoft's 1638 / 3010 / 1641 exit codes as success

If the box has no internet, the prereq install fails with a clear
message and a "continue anyway?" prompt. README + installation docs
list the manual download URLs and `dotnet --list-runtimes` check;
troubleshooting has a section pointing at the same fix when the
service won't start after install.
2026-05-08 14:22:35 -04:00
4 changed files with 171 additions and 1 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ Designed for sysadmins who want to wire up tools like **Zerto pre/post scripts**
## Quickstart
1. **Download** the latest installer: <https://github.com/recklessop/webhook-server/releases/latest>
2. **Run it.** UAC accept → next, next, finish. Adds a Start Menu entry, registers and starts the Windows Service.
2. **Run it.** UAC accept → next, next, finish. Adds a Start Menu entry, registers and starts the Windows Service. The installer also downloads + installs the **.NET 8 runtimes** (ASP.NET Core + Desktop) if they're missing — fresh Windows Server installs need this.
3. **Open Webhook Server** from the Start Menu (auto-elevates).
4. **File → New endpoint**, configure a slug + script, save, hit the URL.
+24
View File
@@ -6,10 +6,34 @@ This page covers a fresh install. If you already have Webhook Server installed,
- Windows 10, Windows 11, or Windows Server 2019 / 2022 / 2025
- Administrator rights to install the service and to run the GUI
- **.NET 8 runtimes** (the installer downloads + installs them automatically if missing — see below)
- (Optional, only if you publish from source) .NET 8 SDK
The installer is **x64 only**. There is no x86 build.
### .NET 8 runtimes
Webhook Server is published as framework-dependent (so the installer stays small) and needs two .NET 8 runtimes on the target machine:
| Runtime | Used by | Auto-installed by setup |
|---|---|---|
| ASP.NET Core 8 Runtime (`Microsoft.AspNetCore.App` 8.x) | the Service / Kestrel | Yes |
| .NET Desktop Runtime 8 (`Microsoft.WindowsDesktop.App` 8.x) | the WPF GUI | Yes |
A clean Windows Server install has neither. The installer detects what's missing and downloads + installs each one silently before copying our files. If the machine has no internet access, install them manually first:
- ASP.NET Core 8 Runtime — <https://aka.ms/dotnet/8.0/aspnetcore-runtime-win-x64.exe>
- .NET Desktop Runtime 8 — <https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe>
Run each with `/install /quiet /norestart` for unattended installs, or just double-click. A reboot is rarely required.
To check what's already installed:
```powershell
dotnet --list-runtimes
# expect to see Microsoft.AspNetCore.App 8.x.y and Microsoft.WindowsDesktop.App 8.x.y
```
## 1. Download
Grab the latest installer from the GitHub Releases page:
+22
View File
@@ -38,6 +38,28 @@ You launched the GUI without elevation. The admin pipe ACL is `SYSTEM` + `Admini
**Fix in v0.1.0**: right-click the Start Menu shortcut → **Run as administrator**, or upgrade.
### Service won't start after install / GUI says "Disconnected" with no obvious error
If `Get-Service WebhookServer` shows it stopped and `Start-Service WebhookServer` fails, or the GUI itself won't even launch, you're probably missing a .NET 8 runtime. The v0.1.4+ installer auto-fetches them, but a clean Windows Server box might still hit this if the install was offline or used an older installer.
Check what's installed:
```powershell
dotnet --list-runtimes
```
You need both:
- `Microsoft.AspNetCore.App 8.x.y` — for the Service
- `Microsoft.WindowsDesktop.App 8.x.y` — for the GUI
If either is missing, install from:
- ASP.NET Core 8 Runtime — <https://aka.ms/dotnet/8.0/aspnetcore-runtime-win-x64.exe>
- .NET Desktop Runtime 8 — <https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe>
Re-run with `/install /quiet /norestart` for unattended installs. Then `Start-Service WebhookServer`.
### "Connection refused" hitting the hook URL
Three possibilities, in order of probability:
+124
View File
@@ -86,6 +86,17 @@ Filename: "powershell.exe"; \
RunOnceId: "RemoveWebhookService"
[Code]
const
// aka.ms redirects to the latest 8.0.x patch. Inno Setup's downloader
// follows redirects via the Windows HTTP stack.
AspNetCore8Url = 'https://aka.ms/dotnet/8.0/aspnetcore-runtime-win-x64.exe';
WinDesktop8Url = 'https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe';
AspNetCore8File = 'aspnetcore-runtime-8.0-win-x64.exe';
WinDesktop8File = 'windowsdesktop-runtime-8.0-win-x64.exe';
var
DownloadPage: TDownloadWizardPage;
function ServiceExists(): Boolean;
var
ResultCode: Integer;
@@ -96,6 +107,119 @@ begin
Result := (ResultCode = 0);
end;
// True if a Microsoft.* shared-framework directory under
// %ProgramFiles%\dotnet\shared contains at least one 8.x.y subfolder.
function HasDotNet8(const RuntimeName: String): Boolean;
var
rec: TFindRec;
base: String;
begin
Result := False;
base := ExpandConstant('{commonpf}\dotnet\shared\') + RuntimeName;
if not DirExists(base) then Exit;
if FindFirst(base + '\8.*', rec) then
try
repeat
if (rec.Name <> '.') and (rec.Name <> '..') and
DirExists(base + '\' + rec.Name) then begin
Result := True;
Exit;
end;
until not FindNext(rec);
finally
FindClose(rec);
end;
end;
function NeedsAspNet8(): Boolean;
begin
Result := not HasDotNet8('Microsoft.AspNetCore.App');
end;
function NeedsWinDesktop8(): Boolean;
begin
Result := not HasDotNet8('Microsoft.WindowsDesktop.App');
end;
procedure InitializeWizard;
begin
DownloadPage := CreateDownloadPage(
'Downloading prerequisites',
'Webhook Server needs the .NET 8 runtimes. Setup is fetching them now.',
nil);
end;
// Runs a downloaded runtime installer silently. Treats Microsoft's
// "success but reboot pending" / "newer already installed" exit codes
// as successes so we don't fail the whole install over a benign result.
function RunRuntimeInstaller(const FileName, DisplayName: String): String;
var
resultCode: Integer;
fullPath: String;
begin
Result := '';
fullPath := ExpandConstant('{tmp}\') + FileName;
if not Exec(fullPath, '/install /quiet /norestart', '', SW_HIDE,
ewWaitUntilTerminated, resultCode) then begin
Result := 'Could not launch the ' + DisplayName + ' installer.';
Exit;
end;
case resultCode of
0, 1638, 3010, 1641: ;
else
Result := DisplayName + ' installer failed (exit code ' +
IntToStr(resultCode) + ').';
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
errMsg: String;
begin
Result := True;
if CurPageID <> wpReady then Exit;
if not (NeedsAspNet8 or NeedsWinDesktop8) then Exit;
DownloadPage.Clear;
if NeedsAspNet8 then
DownloadPage.Add(AspNetCore8Url, AspNetCore8File, '');
if NeedsWinDesktop8 then
DownloadPage.Add(WinDesktop8Url, WinDesktop8File, '');
DownloadPage.Show;
try
try
DownloadPage.Download;
except
if MsgBox('Failed to download the .NET 8 runtimes:' + #13#10#13#10 +
GetExceptionMessage + #13#10#13#10 +
'Continue installing anyway? Webhook Server will not start ' +
'until the runtimes are installed manually.',
mbError, MB_YESNO) = IDNO then
Result := False;
Exit;
end;
finally
DownloadPage.Hide;
end;
if NeedsAspNet8 then begin
errMsg := RunRuntimeInstaller(AspNetCore8File, 'ASP.NET Core 8 Runtime');
if errMsg <> '' then begin
MsgBox(errMsg, mbError, MB_OK);
Result := False;
Exit;
end;
end;
if NeedsWinDesktop8 then begin
errMsg := RunRuntimeInstaller(WinDesktop8File, '.NET Desktop Runtime 8');
if errMsg <> '' then begin
MsgBox(errMsg, mbError, MB_OK);
Result := False;
Exit;
end;
end;
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
ResultCode: Integer;