适用于Windows桌面应用程序的.NET Core 3

介绍

9月,微软发布了新版.NET Core,用于构建Windows桌面应用程序,包括WPF和Windows Forms。从那时起开发人员可以将传统的nfx桌面应用程序(和控件库)迁移到.NET Core。一般使用WPF和Windows Forms开发的业务范围包括:

  • UI密集数据形式(FOD)应用程序
  • 响应式低延迟UI
  • 需要脱机/断开连接运行的应用程序
  • 依赖于自定义设备驱动程序的应用程序

这只是.NET Core上Windows应用程序开发的开始。继续阅读以了解有关.NET Core对构建Windows应用程序更多好处的信息。

为什么在.NET Core上使用Windows desktop?

.NET Core(以及将来在.NET Core之上构建的.NET 5)将是.NET的未来。在未来几年内微软将继续支持.NET Framework,但是不会增加任何新功能,这些新功能只会添加到.NET Core(最终是.NET 5)中。为了改进Windows桌面应用领域,并使.NET桌面开发人员可以从中受益,微软将Windows Forms和WPF引入了.NET Core,但因为与Windows API紧密相关,所以仍将仅支持Windows平台。但是.NET Core除了可以跨平台使用外,还具有许多其他功能,可以增强桌面应用程序。
首先,所有运行时改进和语言功能将仅添加到.NET Core中,以后也将添加到.NET 5中。一个很好的例子是C# 8,它已在.NET Core 3.0中可用。而且Windows Forms和WPF的.NET Core版本将成为.NET 5平台的一部分。
此外,.NET Core通过.NET Framework中不可用的新选项为应用程序带来了部署灵活性,例如:

  • 并行部署
    。可以在同一台计算机上拥有多个.NET Core版本,并且可以选择每个应用程序应针对的版本。
  • 独立部署
    。可以与应用程序一起部署.NET Core平台,并完全独立于最终用户环境。
  • 较小的应用程序大小
    。在.NET Core 3中,微软引入了一个称为链接器(有时也称为微调器)的新功能,该功能将分析代码并将所需的程序集包括在自包含的部署中,不需要的都将被修剪掉。
  • 单个.exe文件
    。可以将应用程序和.NET Core平台打包在一个.exe文件中。
  • 改进了运行时性能
    。与.NET Framework相比,.NET Core具有许多性能优化。具体来说,在很大程度上依赖于I/O操作,网络和数据库操作的桌面应用程序可能会看到这些方面的性能提高。在UI渲染性能或应用程序启动性能有一定的提示,但不是很高。

使用ReadyToRun优化.NET Core应用

通过将应用程序程序集编译为ReadyToRun(R2R)格式,可以缩短.NET Core应用程序的启动时间。R2R是一种提前(AOT)编译的形式。它是.NET Core 3.0中的发布时选择功能。
R2R二进制文件通过减少应用程序加载时JIT需要完成的工作量来提高启动性能。R2R二进制文件较大,因为它们既包含中间语言(IL)代码(某些情况下仍然需要此代码),也包含相同代码的本机版本,以改善启动。
要启用ReadyToRun编译:

  • PublishReadyToRun
    属性设置为 true
  • 使用显式发布 RuntimeIdentifier

注意:编译应用程序程序集时,生成的本机代码特定于平台和体系结构(这就是发布时必须指定有效的RuntimeIdentifier的原因)。
下面是一个例子:

  
    Exe
    netcoreapp3.0
    true
  

并使用以下命令发布:

dotnet publish -r win-x64 -c Release

注意:

RuntimeIdentifier
true

Assembly linking

.NET core 3.0 SDK附带了一个工具,该工具可以通过分析IL和修剪未使用的程序集来减小应用程序的大小。这是.NET Core 3.0中的另一个发布时选择加入功能。
借助.NET Core,始终可以发布包含运行代码所需的一切的自包含应用程序,而无需在部署目标上安装.NET。在某些情况下,该应用仅需要框架的一小部分即可运行,并且可能仅包含所使用的库就可以变得更小。

使用 IL链接器
扫描应用程序的IL,以检测实际需要哪些代码,然后修剪未使用的框架库。这可以大大减小某些应用程序的大小。通常,类似小型工具的控制台应用程序受益最大,因为它们倾向于使用框架的较小子集,并且通常更易于调整。
要使用链接器:

  • PublishTrimmed
    属性设置为 true
  • 使用显式发布 RuntimeIdentifier

下面是一个例子:

  
    Exe
    netcoreapp3.0
    true
  

并使用以下命令发布:

dotnet publish -r win-x64 -c Release

注意: RuntimeIdentifier
可以将其设置为其他操作系统或芯片。也可以在项目文件中设置。
经测试对于helloworld应用程序,大小从〜68MB减小到〜28MB。
修剪后使用反射或相关动态功能的应用程序或框架(包括ASP.NET Core和WPF)通常会中断,因为链接器不了解这种动态行为,并且通常无法确定反射所需的框架类型在运行时。要修剪此类应用程序,您需要告知链接器有关代码中以及依赖的任何包或框架中反射所需要的任何类型。修剪后一定要测试应用程序。针对这个问题微软在.NET 5上正在努力改善。

有关IL Linker的更多信息,请参阅 文档
,或访问 mono / linker存储
库。

注意:在.NET Core的 早期
版本中, ILLink.Tasks
作为外部NuGet软件包提供,并提供了许多相同的功能。请更新到.NET Core 3.0 SDK,然后尝试新的体验!
Assembly linking和ReadyToRun compiler可用于同一应用程序。通常,Assembly linking使应用程序更小,ready-to-run compiler 使应用程序更大一些,但在性能上有明显优势。可以在各种配置中进行测试以了解每个选项的影响。

发布单文件可执行文件

可以使用发布单个文件的可执行文件 dotnet publish
。这种形式的单个EXE实际上是一个自解压缩的可执行文件。它包含所有依赖项(包括本地依赖项)作为资源。在第一次启动时,它将所有依赖项复制到一个临时目录,并在该目录中加载它们。它只需要解压缩依赖项一次。当再次启动时将会很快启动,并且没有任何损失。

可以通过将 PublishSingleFile
属性添加到项目文件或在命令行上添加新的参数来启用此发布选项。
要生成一个独立的单个EXE应用程序,在这种情况下,对于64位Windows:

dotnet publish -r win10-x64 /p:PublishSingleFile=true

注意:

  • RuntimeIdentifier
    可以将其设置为其他操作系统或芯片。也可以在项目文件中设置。
  • 关于临时目录,请参考 Extracting Bundled Files to Disk

有关更多信息,请参见 单文件捆绑器

Assembly trimmer, ahead-of-time compilation(通过crossgen)和单个文件捆绑都是.NET Core 3.0中的所有新功能,可以一起使用,也可以单独使用。

综合使用

通过设置属性




在发布配置文件中,能够将修剪、ahead-of-time compilation后的自包含应用程序部署为单个.exe文件,如下面的示例所示。

    Exe
    netcoreapp3.0
    true
    win-x64
    true
    true
    true

然后使用Visual Studio发布工具或者命令 dotnet publish -c release
发布。

MSIX

如果你正在寻找一种将应用程序分发给最终用户的方法,那么将其打包为 MSIX
可能比创建单个 .exe
文件更好。 PublishSingleFile
提供了一个包含所有应用程序依赖项的自解压ZIP文件,而MSIX提供了干净可靠的Windows集成应用程序安装和卸载。《MSDN杂志》上写了 一篇文章
,不仅展示了如何打包应用程序,而且还展示了如何为MSIX包设置持续集成(CI),持续部署(CD)和自动更新。

.NET Framework desktop 和.NET Core desktop 之间的区别

WPF应用程序在.NET Core上完全受支持。对于Windows Forms,运行时部分已完全移植到.NET Core,并且微软团队正在继续开发 Windows窗体设计器
。微软计划在2020年第四季度之前将其准备就绪,现在可以在 Visual Studio预览下载页面
16.4 Preview 3或更高版本中签出设计器的Preview版本。别忘了在 工具->选项->预览功能->使用.NET Core应用程序的Windows窗体设计器预览,然后重新启动Visual Studio

重大变化

.NET Framework和.NET Core之间有一些 重大更改
,但与Windows窗体和WPF区域相关的大多数代码都按原样移植到了Core。如果使用的组件包括WCF客户端,代码访问安全性,应用程序域,互操作性和远程处理,则要切换到.NET Core,则需要重构代码。
请记住另一件事,.NET Core上的默认输出路径与.NET Framework上的默认输出路径不同,因此,如果在代码中对正在运行的应用程序的文件/文件夹结构进行了一些假设,则它可能会在运行时失败。

此外,配置.NET功能的方式也有所变化。.NET Core而非 machine.config
文件使用的 .runtimeconfig.json
是应用程序随附的文件,该文件具有相同的通用目的和相似的信息。一些配置,如 system.diagnostics
system.net
system.servicemodel
不被支持,那么应用程序配置文件将失败是否含有这些内容的加载。此更改影响 System.Diagnostics
以前使用XML配置通常配置的跟踪和WCF客户端方案。在.NET Core中,需要改为在代码中进行配置。要更改行为而无需重新编译,请考虑使用从 Microsoft.Extensions.Configuration
源或从中加载的值来设置跟踪和WCF类型 appSettings

可以在 .NET Core无法使用的.NET Framework技术
找到有关.NET Core和.NET Framework之间差异的更多信息。

从.NET Framework移植到.NET Core

首先,运行 可移植性分析器
并在需要时更新代码以与.NET Core 100%兼容。这是 有关使用可移植性分析器的说明
。建议在对应用程序进行任何更改之前使用源代码控制或备份代码,以防重构无法按照希望的方式进行。

当应用程序与.NET Core完全兼容时,就可以准备移植它了。首先,可以尝试使用工具 try-convert
以帮助将.NET Framework项目自动转换为.NET Core。
此工具只是通往.NET Core的起点。它也不是受支持的Microsoft产品。尽管它可以帮助解决迁移的某些机械问题,但它不能处理所有方案或项目类型。如果遇到该工具无法转换的项目,则必须手动进行移植。

关于.Net Core3.1的支持

.NET Core 3.1是一个小型且简短的发行版,着重于Blazor和Windows桌面应用(.NET Core 3.0的两个重大改进)的关键改进。这将是一个长期支持(LTS)版本,至少支持3年,预计最终发布日期为2019年12月。

此版本中最大的改进是 对C++/CLI(又称为“托管C++”)的支持