Application Online Upgrade · User Guide

The admin footer shows Powered by EasyAdminBlazor v2.4.0-preview.4 · App v1.0.0 · Check for updates. An administrator clicks Check for updates → Upgrade now; the system stops the app, backs up, replaces files, starts it again and runs a health check. A failed step is rolled back, and users do not have to log in again.

Upgrade packages are per-version deltas: 1.0 → 1.1 → 1.2 are applied one by one, so a client that lags several versions still upgrades automatically (no manual version skipping).

1. Install the extension (pick one)

Online upgrade lives in the EasyAdminBlazor.Upgrade extension. Without it there is no upgrade feature at all: no footer entry, no /health, no upgrade package on publish — existing applications keep behaving exactly as before.

Option A — NuGet (recommended)

<ItemGroup>
  <PackageReference Include="EasyAdminBlazor.Upgrade" Version="2.4.0-preview.4" />
</ItemGroup>

Nothing else is required: the publish hook ships inside the package (build\EasyAdminBlazor.Upgrade.targets) and even the updater binaries are included, so dotnet publish produces updater\ and updates\v<version>\ without any source code.

Option B — source reference (when you work against the framework repository)

<ItemGroup>
  <ProjectReference Include="..\..\yyq\EasyAdminBlazor\Extensions\EasyAdminBlazor.Upgrade\EasyAdminBlazor.Upgrade.Extension.csproj" />
</ItemGroup>

<Import Project="..\..\yyq\EasyAdminBlazor\Extensions\EasyAdminBlazor.Upgrade\build\EasyAdminBlazor.Upgrade.targets" />

Add the three projects to your solution as well, otherwise Visual Studio reports “project information for …EasyAdminBlazor.Upgrade.Extension.csproj was not found” (command-line builds restore them automatically):

Extensions/EasyAdminBlazor.Upgrade/EasyAdminBlazor.Upgrade.Extension.csproj   extension
Extensions/EasyAdminBlazor.Upgrade/Engine/EasyAdminBlazor.Upgrade.csproj      engine
Extensions/EasyAdminBlazor.Upgrade/Updater/EasyAdminBlazor.Updater.csproj     updater + packager

2. Program.cs

var builder = WebApplication.CreateBuilder(args);

// Windows service hosting only (sc create / NSSM)
builder.Host.UseWindowsService();

builder.AddEasyAdminBlazor(new EasyAdminBlazorOptions
{
    // keep your existing settings
})
// your existing extension chain…
.AddEasyAdminBlazorUpgrade();     // enables the upgrade feature (footer entry + /health)

/health is mounted by the extension itself — you never map it yourself.

3. appsettings.json

Windows service (sc create / NSSM):

"Urls": "http://0.0.0.0:5000",
"Upgrade": {
  "Enabled": true,
  "Source": "Local",
  "ReleasesPath": "updates",
  "RestartMode": "WindowsService",
  "ServiceName": "your-service-name",
  "HealthCheckUrl": "http://127.0.0.1:5000"
}

Linux with systemd:

"Urls": "http://127.0.0.1:5000",
"Upgrade": {
  "Enabled": true,
  "Source": "Local",
  "ReleasesPath": "updates",
  "RestartMode": "Systemd",
  "ServiceName": "easyadminblazor",
  "HealthCheckUrl": "http://127.0.0.1:5000"
}

Linux with the BT Panel “.NET project / website” (verified working, no service registration needed):

"Upgrade": {
  "Enabled": true,
  "Source": "Local",
  "ReleasesPath": "updates",
  "RestartMode": "Direct",
  "HealthCheckUrl": "http://127.0.0.1:5018"
}

HealthCheckUrl must be reachable from the server itself (loopback is fine) and must use the same port the app listens on.

4. Publishing (bump the version → publish once)

Only one place holds the version: <Version> in the host csproj (-p:Version=1.1.0 works too).

dotnet publish -c Release -o publish

The output contains the application, updater\ and updates\v<version>\update.zip (+ release.json, files.json, index.json). Optional upgrade notes: release-notes.txt in the project root (one line per note).

5. Deploying a new version to the server

Copy updates/v<new version>/ and updates/index.json into <app>/updates/ on the server, then click “Check for updates → Upgrade now”. Never touch appsettings.json, wwwroot/uploads, .upgrade/.

6. Windows: why “Windows service” is required

An upgrade needs an external process that can stop the app, replace files and start it again. With IIS in-process hosting the app runs inside w3wp.exe (an application pool): recycling/stopping the pool kills the child processes it started (the updater), and the updater is not allowed to stop and restart the whole pool — one pool may even host several sites. The framework therefore disables the upgrade feature when it detects in-process IIS hosting (no footer entry, no /health).

Run the application as an independent process instead: a Windows service with Kestrel, IIS only as a reverse proxy. Then the updater can sc stop/start <service> and bring the app back. Console hosting (RestartMode: Direct) works too but is not recommended for production.

7. Client experience

  • After clicking “Upgrade now” a full-screen overlay shows “Upgrading, please wait…”; rolling upgrades display “step x/y, updating to vN”.
  • Once /health reports the target version, the page shows “Upgrade finished” and reloads automatically after a 3-second countdown; other administrators’ pages reload themselves the same way and nobody has to log in again.
  • The confirmation dialog warns about the current number of online users (they are briefly interrupted).
  • If a step fails, only that step is rolled back and the previous version is started again.

8. Troubleshooting

Symptom What to do
No “Check for updates” in the footer in-process IIS hosting (by design), Upgrade:Enabled is not true, or the account is not an administrator
“Already up to date” the new version folder is not in the server’s updates\, or the host <Version> was not bumped
“Upgrade chain is broken” an intermediate version package is missing — copy it as well
Clicked upgrade but nothing happens and upgrade.log is empty updater/ was not deployed as a whole (updater and engine must be the same version); check the app log for the [升级] 后台启动升级程序:… line
A 502 appears for a few seconds expected: the app is restarting; the overlay and the countdown take care of it
Everyone has to log in again do not change AesKey / CookieName, keep DataProtectionKeyPath on the same directory
Upgrade failed it has been rolled back automatically; send .upgrade/upgrade.log and upgrade-status.json