应用在线升级 · 使用手册
后台底部显示 应用 v1.0.0 · 检查更新。管理员点「检查更新 → 立即升级」,系统自动停服务、备份、替换文件、启动并健康检查,失败自动回滚,用户无需重新登录。
升级包是逐版本增量(1.0 → 1.1 → 1.2 逐版升),落后多个版本会自动依次走完每一步。
升级是扩展:不引用
EasyAdminBlazor.Upgrade,后台就没有「检查更新」入口、不注册/health、发布时也不生成升级包。老项目行为完全不变。
一、安装扩展
方式 A:NuGet(推荐)
<ItemGroup>
<PackageReference Include="EasyAdminBlazor.Upgrade" Version="2.4.0-preview.4" />
</ItemGroup>
一行搞定:扩展本体、升级引擎、发布钩子都在包里,不用写 Import,也不用把任何项目加进解决方案。
方式 B:源码引用(跟随框架源码开发)
<ItemGroup>
<ProjectReference Include="..\..\yyq\EasyAdminBlazor\Extensions\EasyAdminBlazor.Upgrade\EasyAdminBlazor.Upgrade.Extension.csproj" />
</ItemGroup>
<!-- 放在 </Project> 之前 -->
<Import Project="..\..\yyq\EasyAdminBlazor\Extensions\EasyAdminBlazor.Upgrade\build\EasyAdminBlazor.Upgrade.targets" />
源码引用还需要把下面三个项目加进解决方案,否则 VS 会报「找不到项目信息」(命令行 dotnet build/publish 不受影响,会自动连带还原):
Extensions/EasyAdminBlazor.Upgrade/EasyAdminBlazor.Upgrade.Extension.csproj 扩展
Extensions/EasyAdminBlazor.Upgrade/Engine/EasyAdminBlazor.Upgrade.csproj 升级引擎
Extensions/EasyAdminBlazor.Upgrade/Updater/EasyAdminBlazor.Updater.csproj 升级程序 + 打包器
两种方式效果一样:发布时自动把升级程序放进 updater\,Release 配置下自动生成升级包。
二、启用升级
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Windows 服务形态需要;控制台 / 宝塔 可以不加
builder.Host.UseWindowsService();
builder.AddEasyAdminBlazor(new EasyAdminBlazorOptions
{
// …你现有的配置不动…
})
// …你现有的扩展链…
.AddEasyAdminBlazorUpgrade(); // 启用升级(底部「检查更新」+ /health)
/health由扩展自己挂载,宿主不需要写app.MapGet("/health")。宿主原有的app.UseEasyAdminBlazor();保留(它映射消息通知的 SignalR Hub)。
appsettings.json:
Windows 服务:
"Urls": "http://0.0.0.0:5099",
"Upgrade": {
"Enabled": true,
"Source": "Local",
"ReleasesPath": "updates",
"RestartMode": "WindowsService",
"ServiceName": "你的服务名",
"HealthCheckUrl": "http://127.0.0.1:5099"
}
Linux(宝塔):
"Urls": "http://127.0.0.1:5018",
"Upgrade": {
"Enabled": true,
"Source": "Local",
"ReleasesPath": "updates",
"RestartMode": "Direct",
"HealthCheckUrl": "http://127.0.0.1:5018"
}
HealthCheckUrl必须是本机能访问到的地址,端口与站点实际监听端口一致。 想让客户从发布站点点两下升级:Source改成Url,ReleaseIndexUrl填https://你的发布地址/releases/index.json(默认要求 HTTPS,内网 http 需加"AllowInsecureHttp": true)。
三、出包
只改一处:宿主 csproj 的 <Version>。
dotnet publish -c Release -o publish
VS 右键发布(Release 配置)同样有效。发布完成后:
publish\
├── 程序文件 / wwwroot / updater\ ← updater\ 自动生成,别手工删
└── updates\
├── index.json
├── v1.0.0\ update.zip + release.json + files.json ← 上一版(基线)
└── v1.1.0\ update.zip + release.json + files.json ← 本次增量包(约 1~2 MB)
用同一个发布目录连续发布,上一版基线才在,出的是增量包。想写更新说明,在项目根目录放 release-notes.txt,每行一条(# 开头是注释)。
四、Windows 部署(IIS 反向代理 + Kestrel 服务)
环境:安装 .NET 10 Runtime(需要 IIS 支持时装 ASP.NET Core Hosting Bundle),把 publish/ 内容放进应用目录(如 D:\app\EasyAdminBlazor)。
为什么 Windows 下只有在"Windows 服务"形态才能用在线升级?
在线升级要靠外部进程停掉应用、替换文件、再把它拉起来。IIS 进程内托管时应用跑在
w3wp.exe(应用程序池)里: 应用池回收/停止会连带杀掉它启动的子进程(升级程序),升级程序也没有权限把整个应用池停下来再启动; 而且一个应用池可能承载多个站点,停/起粒度对不上。因此框架检测到 IIS 进程内托管时会直接禁用升级入口 (页脚不显示「检查更新」、不注册/health)。所以 Windows 上要让应用以独立进程运行:注册成 Windows 服务(Kestrel 监听本地端口,见下),IIS 只做反向代理; 这样升级程序才能
sc stop/start 服务名停掉并重新拉起应用。控制台运行(RestartMode: Direct)技术上也能升级, 但不适合生产(窗口关掉就没人管了)。
1. 注册为 Windows 服务
管理员命令行:
# 用系统自带的 sc
sc.exe create EasyAdminBlazor binPath= "D:\app\EasyAdminBlazor\你的应用.exe" start= auto
sc.exe start EasyAdminBlazor
# 或者 NSSM
nssm install EasyAdminBlazor "D:\app\EasyAdminBlazor\你的应用.exe"
nssm set EasyAdminBlazor AppDirectory "D:\app\EasyAdminBlazor"
nssm set EasyAdminBlazor Start SERVICE_AUTO_START
nssm start EasyAdminBlazor
验证:http://127.0.0.1:5099/health 应返回
{
"status": "Healthy",
"applicationVersion": "1.0.0",
"frameworkVersion": "2.4.0-preview.4"
}
升级程序会执行:sc stop 服务名 → 等进程退出 → 备份 → 替换 → sc start 服务名 → 检查 /health 版本号。前提是服务账号有控制该服务的权限(sc create 默认的 LocalSystem 即可;受限账号需授予"启动/停止该服务"权限,并保证应用目录可写)。
2. IIS 反向代理配置
- 安装 ARR:IIS 管理器 → 服务器节点 → Application Request Routing Cache → Server Proxy Settings → 勾选 Enable proxy;
- 创建网站:IIS 管理器 → 网站 → 添加网站,物理路径指向一个空目录(用于放
web.config),应用程序池选“无托管代码”; - 放 web.config:在网站根目录放下面这份
web.config(注意把5099改成你实际监听的端口):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyToKestrel" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://127.0.0.1:5099/{R:1}" />
</rule>
</rules>
</rewrite>
<proxy preserveHostHeader="true" />
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="104857600" />
</requestFiltering>
</security>
</system.webServer>
<system.web>
<httpRuntime maxRequestLength="102400" executionTimeout="600" />
</system.web>
</configuration>
说明:
preserveHostHeader="true"保留原始 Host 头,否则 Blazor 的 URL 推导会出错;maxAllowedContentLength放宽到 100MB,覆盖文件上传场景;- 应用程序池必须是无托管代码模式,因为应用是 Kestrel 自托管的。
3. 应用池身份权限
IIS 应用池以 ApplicationPoolIdentity 运行,它需要能访问后端 Kestrel 监听的端口(127.0.0.1:5099)。因为是本机回环,通常无需额外配置。但如果站点报 502,检查 IIS 是否能访问该端口:
curl http://127.0.0.1:5099/health
如果这条命令在服务器上能通,IIS 的反代就没有问题。
五、Linux 宝塔部署(已实测可用,无需注册服务)
不需要注册 systemd 服务,也不要用宝塔的「进程守护」——直接用宝塔自带的 .NET 网站功能发布即可,升级程序会自己停/起进程。
- 发布:本机
dotnet publish -c Release -o publish,把publish/整个传到/www/wwwroot/your-app; - 建站点:宝塔 → 网站 → 添加站点 → 选择 .NET 项目 / .NET 网站,项目目录指向
/www/wwwroot/your-app,启动文件你的应用.dll,端口按宝塔给的(例如 5018); - 确认端口:站点启动参数是
--urls http://localhost:5018,appsettings.json里的HealthCheckUrl用同一个端口http://127.0.0.1:5018; - 配置:
appsettings.json用第二节里 Linux 那份(RestartMode: "Direct",端口 5018); - 升级:把新版本的
updates/v1.1.0/和updates/index.json传到<应用目录>/updates/,后台点「检查更新 → 立即升级」。
权限要点:应用目录要可写(升级要写 .upgrade/ 和程序文件),属主建议给 www。
六、把新版本发到服务器
服务器不需要重新部署程序,只把一个目录拷过去:
服务器 <应用目录>/updates/ ← 放入新版本目录(如 v1.1.0/)
然后管理员登录后台 →「检查更新」→「立即升级」,等页面自动刷新即可。升级期间服务停几十秒,页面自动重连,不用重新登录。
首次部署新服务器:把整个 publish/ 拷过去(已带 updates/v1.0.0/ 基线),之后每版只传增量目录(实测如果嫌基线版本占空间不放也行)。