ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

mRemoteNG 双轨部署方案全解析:Framework-Dependent 与 Self-Contained 构建实战

mRemoteNG 双轨部署方案全解析:Framework-Dependent 与 Self-Contained 构建实战 mRemoteNG 双轨部署方案全解析Framework-Dependent 与 Self-Contained 构建实战【免费下载链接】mRemoteNGmRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager.项目地址: https://gitcode.com/gh_mirrors/mr/mRemoteNGmRemoteNG 是开源的多协议远程连接管理器其 .NET 10 时代引入的两种部署形态——框架依赖版Framework-Dependent简称 FD与自包含版Self-Contained简称 SC——直接决定了产物大小、运行时依赖与分发策略。本文以仓库根目录下的 DEPLOYMENT_OPTIONS.md 为核心骨架结合 mRemoteNG.csproj、ProgramRoot.cs 与 CI 工作流等源码证据完整讲解两种部署类型的差异、本地构建命令、编译常量机制、自动发布流程以及验证与迁移方法。读完本文你将能独立构建、验证并发布 x64 / ARM64 双架构、FD / SC 双形态的 mRemoteNG 安装包。一、两种部署类型的定位与取舍mRemoteNG 的发布产物通过文件后缀区分-FD.zip表示框架依赖版-SC.zip表示自包含版。两者的本质区别在于是否把 .NET 运行时打包进产物。维度Framework-DependentFDSelf-ContainedSC文件后缀-FD.zip-SC.zip体积约 15~25 MB约 80~150 MB前置条件用户需自行安装 .NET 10 Desktop Runtime无运行时已内置启动行为检查 .NET 运行时与 Visual C Redistributable缺失时提示下载不做运行时检查运行时已打包典型场景面向可接受安装前置依赖的标准用户U 盘便携、受限环境、零安装配置需求FD 版体积小、更新快且可与系统上其他 .NET 应用共享运行时适合作为标准发行版SC 版虽然体积接近百 MB但解压即用无需任何前置环境准备是便携部署的唯一选择。从 mRemoteNG.csproj 可以看到工程显式声明了ConfigurationsDebug;Release;Release Self-Contained;Deploy to github四种配置其中Release Self-Contained就是为自包含构建单独设计的编译配置印证了双轨发布是官方一等公民能力。体积差异的根源SC 版额外携带了整个 .NET 10 运行时约 80 MB 的固定开销这是文档中Self-contained includes entire .NET 10 runtime (~80 MB overhead)的直接来源。二、本地构建Framework-Dependent 版FD 构建走传统的 MSBuild 路径使用msbuild直接编译解决方案# x64 msbuild mRemoteNG.sln -p:ConfigurationRelease -p:Platformx64 # ARM64 msbuild mRemoteNG.sln -p:ConfigurationRelease -p:PlatformARM64此命令会以Release配置编译 mRemoteNG.sln仓库根目录下的全部工程。对应到 mRemoteNG.csprojRelease|x64与Release|arm64两个属性组不定义任何特殊编译常量、不设置RuntimeIdentifier输出分别落入bin\x64\Release\与bin\arm64\Release\产物即纯框架依赖形态。三、本地构建Self-Contained 版SC 构建需要dotnet publish指定运行时标识RID并开启自包含开关# x64 dotnet publish mRemoteNG\mRemoteNG.csproj --configuration Release --runtime win-x64 --self-contained true -p:Platformx64 -p:PublishSingleFilefalse -p:PublishReadyToRuntrue -p:DefineConstantsSELF_CONTAINED # ARM64 dotnet publish mRemoteNG\mRemoteNG.csproj --configuration Release --runtime win-arm64 --self-contained true -p:PlatformARM64 -p:PublishSingleFilefalse -p:PublishReadyToRuntrue -p:DefineConstantsSELF_CONTAINED参数逐一说明--runtime win-x64 / win-arm64目标运行时标识与 mRemoteNG.csproj 中声明的RuntimeIdentifierswin-x64;win-arm64对应--self-contained true将 .NET 10 运行时整体打包-p:PublishSingleFilefalse保持文件分离。这一选择与 mRemoteNG 的插件机制强相关——工程中通过CopyPackageAssembliesToSubFolderTarget见 mRemoteNG.csproj把 NuGet 依赖程序集统一落到Assemblies\子目录由 ProgramRoot.cs 中的OnAssemblyResolve事件按需加载单文件发布会破坏这种程序集延迟解析布局-p:PublishReadyToRuntrue启用 ReadyToRunR2R预编译将 IL 预编译为原生代码缩短冷启动时间代价是体积略有增加-p:DefineConstantsSELF_CONTAINED定义编译常量详见第五节。另一种等效方式工程内置的 Release Self-Contained 配置除了命令行传参仓库还内置了完整的自包含构建配置。在 mRemoteNG.csproj 中Release Self-Contained|x64/arm64属性组已经写死了SelfContainedtrue、RuntimeIdentifierwin-x64/win-arm64、PublishReadyToRuntrue与DefineConstantsPORTABLE因此直接执行msbuild mRemoteNG\mRemoteNG.csproj -p:ConfigurationRelease Self-Contained -p:Platformx64即可触发构建。更关键的是工程末尾的PublishAfterBuildTargetmRemoteNG.csproj会在该配置构建完成后自动级联执行Publish目标并把临时编译目录清理掉最终发布产物落在bin\x64\Publish Self-Contained\x64与bin\arm64\Publish Self-Contained\arm64。CI 工作流正是复用了这套配置见第六节。四、启动时的运行时检查源码级实现FD 版与 SC 版在启动行为上的差异体现在 ProgramRoot.cs 的MainAsync入口中。实际实现比文档中描述的#if直接裁剪要更精细——代码通过ShouldSkipNativeRuntimeChecks(args)统一决策自包含构建IsPortableBuild为 true直接跳过整个检查块private static Task MainAsync(string[] args) { AppDomain.CurrentDomain.AssemblyResolve OnAssemblyResolve; if (!ShouldSkipNativeRuntimeChecks(args)) { // Runtime checks only needed for framework-dependent deployments // Self-contained builds include the runtime, so no check is needed // Note: .NET runtime check is not needed here — the .NET host (apphost) // natively displays a missing-runtime dialog with a download link. var checkFail false; // Checking Visual C Redistributable version if (VCppRuntimeCheck.GetInstalledVcRedistVersions() null || VCppRuntimeCheck.GetInstalledVcRedistVersions().Count 0) { // 弹出 Download/Cancel 对话框引导用户下载 vc_redist.x64.exe // ... checkFail true; } if (checkFail) { Environment.Exit(0); } } // ... }这里有两点值得注意的源码细节.NET 运行时缺失的提示并非由应用代码完成源码注释明确指出apphost.NET 生成的应用程序宿主在运行时缺失时会原生弹出带下载链接的对话框因此MainAsync只需关心Visual C Redistributable是否安装VC 运行时的检测逻辑位于 VCppRuntimeCheck.cs它遍历注册表SOFTWARE\Microsoft\VisualStudio与SOFTWARE\WOW6432Node\Microsoft\VisualStudio下14.0 ~ 17.3各版本的VC\Runtimes\x64键检查Installed值是否为 1一旦检测到缺失应用会弹出含下载链接的对话框并在用户确认后通过Process.Start打开https://aka.ms/vs/17/release/vc_redist.x64.exe下载页随后Environment.Exit(0)退出。检查的绕过机制ProgramRoot.cs 的ShouldSkipNativeRuntimeChecks提供了三套跳过途径对运维和排障很有价值便携构建IsPortableBuild即#if PORTABLE常量见 ProgramRoot.cs为 true 时直接跳过命令行开关启动参数携带--skip-runtime-checks不区分大小写时跳过环境变量设置MREMOTENG_SKIP_RUNTIME_CHECKS1或true/TRUE时跳过。这些分支均有单元测试覆盖mRemoteNGTests/App/ProgramRootTests.cs中的ShouldSkipNativeRuntimeChecks_WhenCliSwitchIsProvided_ReturnsTrue、ShouldSkipNativeRuntimeChecks_WhenEnvironmentRequestsBypass_ReturnsTrue以及验证无任何绕过配置时行为等于ProgramRoot.IsPortableBuild的测试完整对应上述三条路径。关于编译常量的一点勘误DEPLOYMENT_OPTIONS.md 中提到以SELF_CONTAINED常量配合#if !SELF_CONTAINED裁剪运行时检查代码从当前仓库的实际代码看自包含裁剪实际由PORTABLE常量承担mRemoteNG.csproj 中Release Self-Contained配置定义的是DefineConstantsPORTABLEProgramRoot.IsPortableBuild同样检测PORTABLE。可以推断SELF_CONTAINED是文档撰写时构想的命名实际落地沿用了历史遗留的PORTABLE符号两者功能等价——编译进自包含产物的二进制中不再包含 VC 运行时检查逻辑。五、PORTABLE 符号对相关模块的连锁影响PORTABLE不只是控制启动检查它还在全仓库多处条件编译直接影响自包含版的运行行为更新机制AppUpdater.cs非便携版#if !PORTABLE下载更新后保存到系统临时目录并静默安装 MSI便携版则弹出SaveFileDialog让用户选择保存位置由用户手动替换文件更新源UpdateChannelInfo.cs定义了update-portable.txt、preview-update-portable.txt、nightly-update-portable.txt等独立的便携版更新通道文件配置读写DockPanelLayoutLoader.cs、ExternalAppsLoader.cs、ChooseProvider.cs中均有#if !PORTABLE/#if PORTABLE分支决定界面布局、外部工具清单与数据源选择器在便携形态下的行为UI 呈现FrmAbout.cs中[Conditional(PORTABLE)]方法会在关于窗口标注便携版身份。可见从免安装这一需求出发PORTABLE贯穿了更新、配置与 UI 三条链路SC 版不是简单的FD 版加运行时而是一套经过条件编译裁切的完整便携形态。六、GitHub Actions一次构建四种产物的自动化流水线仓库 .github/workflows/Build_mR-NB.yml 是文档中提到的多部署工作流工作流name为Build_and_Release_mR-NB_MultiDeploy。它通过矩阵策略一次产出四种变体变体产物命名示例runnerx64 Framework-DependentmRemoteNG-YYYYMMDD-vX.X.X-NB-XXXX-x64-FD.zipwindows-2025-vs2026x64 Self-ContainedmRemoteNG-YYYYMMDD-vX.X.X-NB-XXXX-x64-SC.zipwindows-2025-vs2026ARM64 Framework-DependentmRemoteNG-YYYYMMDD-vX.X.X-NB-XXXX-arm64-FD.zipwindows-11-vs2026-armARM64 Self-ContainedmRemoteNG-YYYYMMDD-vX.X.X-NB-XXXX-arm64-SC.zipwindows-11-vs2026-arm触发条件工作流仅在两种情况下运行见 Build_mR-NB.yml 的if表达式推送触发向v1.78.2-dev分支推送且最新提交信息包含NB release手动触发通过workflow_dispatch手动运行带release_flag输入默认true。流水线关键步骤检出代码actions/checkoutv7自动发现解决方案递归查找.sln或.slnx文件兼容新老格式安装 .NET 10 SDKactions/setup-dotnetv6并配置 MSBuildmicrosoft/setup-msbuildv3按矩阵选择 msbuild 架构解析 MSBuild 环境定位msbuild.exe、SDK 基础路径写入MSBuildSDKsPath、DOTNET_ROOT等环境变量保证 MSBuild 能找到正确的 .NET SDKT4 模板转换安装dotnet-t4工具将 AssemblyInfo.tt 按矩阵平台转换生成AssemblyInfo.cs版本号即来自此文件NuGet 恢复FD 用Release配置恢复SC 用Release Self-Contained配置并追加-p:SelfContainedtrue -p:RuntimeIdentifierwin-{arch} -p:PublishReadyToRuntrue恢复且缓存键按架构与部署类型区分构建FD 走msbuild /p:ConfigurationReleaseSC 走msbuild /p:ConfigurationRelease Self-Contained同时把PublishDir指到bin\{Platform}\{arch}\Release生成发布信息从AssemblyInfo.cs正则提取AssemblyVersion得到版本与构建号拼出 zip 名与 tag格式yyyyMMdd-vX.X.X-NB-(build)并抓取最近一次提交信息提取 CHANGELOG自动截取 CHANGELOG.md 最新版本段作为发布说明正文压缩与上传Compress-Archive打包整个输出目录为 zip作为 artifact 上传保留 1 天。合并发布NB-Build-and-Release完成后Create-Combined-Release作业汇总四个 artifact调用softprops/action-gh-release创建单一 GitHub Releasetag 与名称统一如mRemoteNG vX.X.X NB (build)发布说明中明确标注Framework-Dependent (FD)需安装 .NET 10 Runtime体积约 15~25 MB文件为*-FD.zipSelf-Contained (SC)便携免安装体积约 80~150 MB文件为*-SC.zip并以prerelease: true发布正文附带 CHANGELOG 与最近提交信息。整个流水线在仓库侧即可一次触发、四包齐发、合并发布无需手工处理各平台产物。七、如何选择用户视角与分发视角面向终端用户选 Framework-DependentFD如果不介意一次性安装 .NET 10 Desktop Runtime希望下载体积小15~25 MB机器上已运行多个 .NET 应用愿意共享同一运行时。选 Self-ContainedSC如果希望零安装、零配置解压即用需要 U 盘等便携介质携带受限环境、无管理员权限的机器不想处理任何前置依赖。面向分发者将FD 作为默认/推荐选项体积小、更新发布快、与系统共享运行时适合大多数常规用户将SC 作为便携替代覆盖特殊场景隔离网络、临时工作站、企业脱管设备两种形态互补而不是互斥。当前 CI 工作流的四个包合并到一个 Release设计正是这一策略的落地。八、发布前验证清单文档给出了两组手工验收步骤分别验证 FD 与 SC 的运行时处理逻辑Framework-Dependent 版卸载 .NET 10 Runtime若已安装运行mRemoteNG.exe应弹出 .NET 10 Runtime 下载提示由 apphost 原生触发安装运行时后再次启动确认应用正常进入主界面。Self-Contained 版卸载 .NET 10 Runtime若已安装运行mRemoteNG.exe应直接启动、无任何运行时检查提示验证完整功能连接、配置读写、插件加载等。结合第五节可知SC 版还应顺带验证便携更新流程保存对话框与便携配置路径是否按预期工作因为PORTABLE符号同时裁切了这两部分逻辑。九、从旧工作流迁移仓库同时保留了旧版单工作流。若此前一直使用Build_and_Release_mR-NB.yml发布单一版本迁移到多部署方案只需三步重命名或删除旧工作流Build_and_Release_mR-NB.yml仓库当前实际路径为 .github/workflows/Build_mR-NB.yml其name已是Build_and_Release_mR-NB_MultiDeploy可直接复用将新工作流重命名为Build_and_Release_mR-NB.yml若需要保持既有触发配置的命名习惯提交并推送提交信息中包含NB release以触发四变体构建。迁移后Release 页将从单个 zip变为x64/ARM64 × FD/SC 四个 zip 加清晰说明的结构用户可按需取用。十、总结mRemoteNG 的双轨部署是一套工程配置 条件编译 CI 矩阵三层配合的完整方案工程层通过Release Self-Contained配置固化自包含参数mRemoteNG.csproj代码层通过PORTABLE常量统一裁切运行时检查、更新与配置行为ProgramRoot.cs、AppUpdater.cs流水线层通过矩阵策略一次产出四种产物并合并发布Build_mR-NB.yml。无论是本地手动构建 FD/SC 包还是维护自动化发布理解这三层之间的联动关系都是关键。按本文第七、八节的策略与清单执行即可稳定交付满足不同用户群体需求的 mRemoteNG 发行版。【免费下载链接】mRemoteNGmRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager.项目地址: https://gitcode.com/gh_mirrors/mr/mRemoteNG创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进