Bootstrap

.net无运行时发布原理

一、引言

在.NET 的演进历程中,每一次版本的更迭都如同一颗投入湖面的石子,激起层层创新的涟漪。而.NET 6,无疑是其中一颗璀璨的明珠,其作为微软推出的重要里程碑版本,为开发者带来了诸多令人眼前一亮的新特性与优化。

在这些革新之中,支持自包含部署(self - contained deployments)尤为引人注目。这一特性宛如赋予了程序一个 “移动城堡”,将应用程序及其运行时紧密打包成一个可执行文件。如此一来,程序便拥有了在没有预先安装.NET 运行时的机器上自由驰骋的能力。

然而,这是否就意味着.NET 6 程序真的能够毫无顾虑地 “裸奔” 呢?在看似美好的表象之下,是否还隐藏着一些我们尚未察觉的细节与挑战?接下来,就让我们一同深入这片技术的神秘森林,揭开.NET 6 程序自包含部署的神秘面纱 ,探寻其背后的真相。

二、什么是自包含部署

在传统的.NET Core 应用发布领域,存在着两种截然不同的部署模式,如同两条分岔的道路,各自引领着程序走向不同的运行环境,它们分别是框架依赖部署(framework - dependent deployment, FDD)和自包含部署(self - contained deployment, SCD)。

框架依赖部署(FDD)模式下,程序运行前,目标机器必须预先安装好.NET 运行时 ,就像一场演出需要提前搭建好舞台、准备好基础设备一样。这意味着,若目标机器没有安装对应的.NET 运行时,程序将无法顺利启动,就如同演员站在没有布景和道具的空地上,无法呈现完整的表演。

而自包含部署(SCD)则为我们带来了一种全新的体验。在这种模式下,应用程序仿佛化身成为一个自给自足的 “小宇宙”,它将自身运行所需的.NET 运行时紧紧包裹在其中。如此一来,即便目标机器上没有预装.NET 运行时,这个 “小宇宙” 也能凭借自身携带的 “能量”—— 运行时,正常地运转起来 。例如,当我们将一个采用自包含部署的应用程序部署到一台全新的、未安装任何.NET 运行时的服务器上时,它依然可以顺利启动并提供服务,就像一艘自带所有物资和设备的太空飞船,能够在没有外部补给的情况下,在太空中独立执行任务。

三、如何启用自包含部署

3.1 修改.csproj 文件

在开启自包含部署的征程中,修改项目文件(.csproj)是关键的第一步 。这就如同为一艘即将远航的船只精心调整航向,确保它能驶向正确的目的地。

打开你的项目文件,在其中的标签内,我们需要进行一系列关键的设置。首先,要确保标签中指定了目标运行时的标识符,这如同为船只标注了明确的航线坐标。例如,若你的应用程序需要在 Windows、macOS 和 Linux 的 64 位系统上运行,那么可以这样设置:win - x64;osx - x64;linux - x64。

而最为核心的设置,则是将标签的值设置为true。这一操作就如同为船只配备了充足的燃料和物资,使其能够在没有外部补给的情况下独立航行。当标签设置为true时,它向编译器传达了一个明确的指令:生成一个自包含的应用程序,将所有运行时的依赖都打包进来。

如下所示为一个完整的设置示例:

<Project Sdk="Microsoft.NET.Sdk.Web">
    <!-- 其他配置项 -->
    <PropertyGroup>
        <RuntimeIdentifiers>win - x64;osx - x64;linux - x64</RuntimeIdentifiers>
        <SelfContained>true</SelfContained>
    </PropertyGroup>
</Project>

通过这样的设置,我们的项目就已经做好了准备,为后续生成自包含的部署包奠定了坚实的基础。

3.2 发布应用程序

在完成了项目文件的关键设置后,接下来就是见证奇迹的时刻 —— 发布应用程序。这一步就如同将精心打造的船只推放入海,让它驶向广阔的应用领域。

在命令行中,我们使用以下强大的命令来发布应用程序:dotnet publish -c Release -o out。这条命令就像是一把神奇的钥匙,能够开启通往自包含部署的大门。

其中,dotnet publish是发布应用程序的核心命令,它负责将我们的项目代码进行编译、打包等一系列复杂的操作。-c Release表示我们以发布版本(Release)的配置进行发布。在 Release 配置下,编译器会对代码进行优化,去除调试信息等不必要的内容,使生成的应用程序更加高效、精简。而-o out则指定了输出目录为out。这意味着,经过编译和打包后的所有文件,包括应用程序的可执行文件、程序集文件、.NET 运行时的所有 DLL 文件以及其他必要的资源文件,都将被整齐地放置在out目录中。

当我们在命令行中输入并执行这条命令后,编译器会迅速行动起来,按照我们的配置要求,将项目转换为一个自包含的部署包。这个过程可能需要一些时间,具体取决于项目的规模和复杂程度。但当一切完成后,我们会在指定的out目录中看到一个完整的、自给自足的应用程序世界。这里面的所有内容,都为我们的应用程序在没有预装.NET 运行时的环境中顺利运行提供了保障。

四、深度解析自包含部署

4.1 输出目录的内容

当我们成功执行发布命令后,满怀期待地打开指定的输出目录,仿佛打开了一个充满宝藏的宝箱,里面的内容为我们的应用程序在新环境中顺利运行提供了全方位的支持。

在这个神奇的目录中,首先映入眼帘的是应用程序的可执行文件,它如同整个应用程序的 “指挥官”,负责发号施令,启动整个应用程序的运行流程。例如,对于一个名为 “MyApp” 的应用程序,其可执行文件可能是 “MyApp.exe”(在 Windows 系统下) 。这个文件是我们与应用程序交互的直接入口,通过双击它(在图形化界面中)或在命令行中输入其名称并执行,就能唤醒沉睡的应用程序,让它开始为我们服务。

紧接着,我们会看到一系列的程序集文件。这些程序集文件就像是应用程序的 “智囊团”,它们包含了应用程序的核心代码逻辑、各种功能模块以及所依赖的类库等。每一个程序集文件都各司其职,共同协作,实现应用程序的各种复杂功能。例如,一个包含用户界面逻辑的程序集文件,负责处理用户与应用程序之间的交互,如按钮点击、文本输入等操作;而另一个包含数据访问逻辑的程序集文件,则负责与数据库进行通信,实现数据的存储、读取和更新等操作 。

而最为关键的,当属.NET 运行时的所有 DLL 文件。这些 DLL 文件宛如应用程序的 “生命支持系统”,它们为应用程序的运行提供了必要的运行时环境、基础类库、执行引擎等核心组件。无论是内存管理、垃圾回收,还是代码的编译与执行,都离不开这些 DLL 文件的支持。例如,mscorlib.dll 是.NET 运行时的核心库之一,它提供了许多基础的类型和功能,如整数、字符串的处理,以及基本的输入输出操作等 。没有这些 DLL 文件,应用程序就如同失去了氧气的生命,无法正常运转。

此外,输出目录中还包含了其他必要的资源文件。这些资源文件种类繁多,可能包括应用程序的配置文件,如 appsettings.json 或 web.config,它们存储了应用程序的各种配置信息,如数据库连接字符串、日志级别等,就像是应用程序的 “设置手册”,指导应用程序如何根据不同的环境和需求进行运行;也可能包括图片、图标、样式表等文件,这些文件为应用程序的用户界面提供了丰富的视觉元素,使其更加美观、易用,就像是为应用程序穿上了一件漂亮的外衣。

4.2 运行自包含的应用程序

当我们拥有了这个包含一切所需的输出目录后,就如同拥有了一个装满魔法道具的百宝箱,接下来就是见证魔法施展的时刻 —— 将应用程序部署到目标机器上并运行它。

这个过程非常简单,就像把一件珍贵的礼物从一个地方搬到另一个地方一样。我们只需要将整个输出目录完整地复制到目标机器上。这个目标机器可以是一台全新的、未安装任何.NET 运行时的服务器,也可以是一台普通的个人电脑,甚至是一台处于不同网络环境的远程设备。

例如,我们将输出目录命名为 “out”,并将其复制到目标机器的 “C:\MyApp” 目录下。接下来,要运行应用程序,只需在目标机器上找到应用程序的可执行文件,然后通过双击(在图形化界面中)或在命令行中输入其完整路径并执行的方式来启动它。在命令行中,我们可以进入到应用程序可执行文件所在的目录,然后输入类似 “C:\MyApp\out\MyApp.exe” 的命令(假设 “MyApp.exe” 是应用程序的可执行文件),按下回车键后,应用程序便会在这台没有预装.NET 运行时的机器上欢快地运行起来 。

此时,我们会看到应用程序按照我们预先设计的逻辑开始工作,展示出其丰富的功能和界面。无论是提供网页服务、处理数据计算,还是与用户进行交互,它都能如在开发环境中一样,稳定而高效地运行。这一切都得益于自包含部署的强大能力,它让我们的应用程序摆脱了对目标机器上预先安装.NET 运行时的依赖,真正实现了 “随时随地,开箱即用” 的便捷部署体验。

五、注意事项

尽管自包含部署为我们的应用程序带来了前所未有的便携性和独立性,宛如赋予了程序一双自由翱翔的翅膀,但在实际应用中,我们也需要清醒地认识到它所带来的一些挑战和需要特别关注的地方 。

首先,最为直观的问题就是文件大小的显著增加。由于自包含部署模式下,应用程序需要将完整的.NET 运行时一同打包,这就好比为一个旅行的人配备了一整套齐全的装备,从衣物到工具,应有尽有。虽然这些装备能确保在任何环境下都能应对自如,但不可避免地会使行李变得沉重。对于应用程序而言,这意味着生成的可执行文件体积会大幅膨胀。例如,一个原本可能只有几兆字节的应用程序,在采用自包含部署后,其文件大小可能会飙升至几十甚至上百兆字节 。这不仅会增加应用程序的下载时间和带宽消耗,对于一些存储资源有限的设备,如移动设备或老旧的电脑,可能还会面临存储空间不足的问题,从而影响应用程序的部署和使用。

其次,当我们的应用程序需要跨越不同的操作系统平台运行时,自包含部署也带来了一些额外的复杂性。由于不同操作系统的内核、文件系统、运行时环境等存在差异,我们无法使用一个通用的自包含部署包来满足所有平台的需求。这就如同我们需要为不同身材和喜好的人定制不同的服装一样,对于每个目标操作系统平台,我们都需要分别进行发布操作 。例如,若我们的应用程序需要同时在 Windows、macOS 和 Linux 系统上运行,那么我们就需要针对这三个平台各自生成对应的自包含部署包。这不仅增加了开发和部署的工作量,还需要我们对每个平台的特性和要求有深入的了解,以确保应用程序在各个平台上都能稳定、高效地运行 。在实际操作中,可能会遇到一些平台特定的问题,如某些依赖库在某个平台上的兼容性问题,或者是文件路径格式、权限设置等方面的差异,这些都需要我们在开发和测试过程中特别留意,以避免在部署到不同平台时出现意想不到的错误。

六、结论

经过一番深入的探究,我们清晰地认识到,自包含部署宛如一把神奇的钥匙,为.NET 6 程序开启了在未预装.NET 运行时环境中自由运行的大门,使得 “裸奔” 这一看似大胆的设想成为了现实。

但与此同时,我们也不能忽视这一部署方式所带来的挑战。文件体积的增大,犹如为程序的传播披上了一层厚重的铠甲,在一定程度上限制了其在网络传输和存储资源有限环境中的灵活性;而针对不同平台的分别发布,也如同为开发者增添了额外的 “任务关卡”,要求我们投入更多的精力和时间。

在实际的项目开发与部署过程中,开发者们需要像经验丰富的航海家一样,在应用程序的便携性与资源占用之间,精准地找到平衡的坐标。根据项目的具体需求、目标受众以及运行环境等多方面因素,综合考量,审慎抉择。

自包含部署无疑为.NET 应用程序的分发注入了一股全新的活力,提供了一种更加灵活、便捷的选择。它让开发者们能够从繁琐的环境配置中解脱出来,将更多的智慧与热情投入到应用程序本身的创新与优化之中。相信在未来,随着技术的持续进步与完善,.NET 程序的部署方式将变得更加高效、智能,为我们带来更多意想不到的惊喜与可能 。

;