Dotnet Core应用跨框架版本运行
dotNET跨平台 今天
以下文章来源于老王Plus ,作者老王Plus的老王
有时候,我们真想用新框架,可也真不想改代码。
有一个前置的知识需要了解,就是微软 Dotnet Core 框架的版本体系。我前边的文章「Dotnet Core使用特定的SDK&Runtime版本」有详细的说明,可以去翻翻看。
前言
有一个旧应用,是在 Dotnet Core 2.1 下编译的服务端应用。本来跑的很好。最近,服务器上的 Dotnet Core Runtime 框架统一升级到 3.1,于是,这个程序就出问题了。
运行时,会报以下的错误:
% dotnet theapp.dll It was not possible to find any compatible framework versionThe framework 'Microsoft.NETCore.App', version '2.1.0' was not found. - The following frameworks were found: 3.1.11 at [/usr/share/dotnet/shared/Microsoft.NETCore.App]
You can resolve the problem by installing the specified framework and/or SDK.
The specified framework can be found at: - https://aka.ms
为什么会这样?
这个情况,源于微软的默认框架运行规则:Dotnet Core 应用运行时,要求运行时的版本,主版本号与编译程序的SDK版本相同,次版本号等于或高于编译程序的SDK版本。
比方我们上边这个程序,编译 SDK 的版本是 2.1.0,因此默认可以运行在装有 Dotnet Runtime 2.1.0 - 2.1.28 的所有运行时下。
但是,现实的情况,我们希望升级框架的主版本。要知道,现在 Dotnet 5.0 已经成为常规版本,6.0 也已经到了第五个 Preview 了,升级是必然的。
那么,升级完框架后,如何升级已有的应用?
如何升级已有的应用?
通常会有这么几种方式,来升级已有的应用:
1. 升级应用的编译 SDK 版本
说白了,就是在指定的新的 SDK 版本下,重新编译重新生成。
指定特定的 SDK 版本,只需要打开对应工程的.csproj
文件,在里面加入下面的内容:
<PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework></PropertyGroup>
这里面,我们以指定 Dotnet 3.1 为例子。
这儿要注意,5.0 之前,TargetFramework 对应的名称为 netcoreapp,例如 netcoreapp2.1、netcoreapp3.1,而 5.0 之后,微软把名称改了,变成了 net5.0、net6.0。
这个方式,算是几种方式中,比较麻烦的一种。最基本的前提是,要有工程的源代码。
如果没有源代码,又该怎么办呢?
2. 显式覆盖运行时
Dotnet 命令行有一个参数,可以显式指定使用特定运行时版本来覆盖编译版本对应的运行时。
这个参数就是 --fx-version。
使用时,命令如下:
% dotnet --fx-version "3.1.11" theapp.dll
还是上面的例子,这样一个命令,就可以让 2.1.0 下编译的应用,在 3.1.11 的运行时下运行。而这个 3.1.11,就是安装的运行时的版本号。
如果不知道已安装的运行时的准确版本号,可以用以下命令查询:
% dotnet --list-runtimesMicrosoft.AspNetCore.App 3.1.11 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]Microsoft.NETCore.App 3.1.11 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
3. 显式覆盖 .runtimeconfig.json 文件
这是另一种显式改变运行时的方式。
我们观察项目的编译结果目录,会看到一个跟随应用的 .runtimeconfig.json 文件。以上面的例子来说,会叫做 theapp.runtimeconfig.json。如果没有,可以手工创建一个。
看一下它的内容:
{ "runtimeOptions": { "tfm": "netcoreapp2.1", "framework": { "name": "Microsoft.NETCore.App", "version": "2.1.0" } }}
在这个配置文件中,微软提供了一个前滚策略,可以通过 rollForward 来定义如果找不到要求的运行时版本,程序应该如果使用其它版本的运行时。
关于 rollForward 的详细说明,在「Dotnet Core使用特定的SDK&Runtime版本」文章中也有详细的说明,这儿就不再赘述了。我们直接看内容本例的修改内容:
{ "runtimeOptions": { "tfm": "netcoreapp2.1", "framework": { "name": "Microsoft.NETCore.App", "version": "2.1.0", "rollForward": "major" } }}
比较前后两个文件,只是在中间加了一行:"rollForward": "major",就让这个程序在高版本的运行时下正常运行了。
重要的问题
嗯,虽然上面写了三种方式跨框架运行,但是,你一定要注意,跨框架运行,不像看上去那么简单。
你可以去骂微软。微软在做 Dotnet 主要版本的升级时,是有破坏性的更改的。也就是说,后面的版本,并不是完全兼容前边的版本的。某些类或方法,在版本升级时,都可能做了新的设计和变更,一些方法会被取消,甚至连所属的软件包,都可能发生变化。
因此,做完上面的工作后,要做仔细全面的测试。一个应用可以工作得很好,不等于每个应用都可以。
额外的内容:SDK 与 Runtime
在 Dotnet Core 体系中,SDK 与 Runtime 是完全分离的。虽然我们每次安装时,SDK 与 Runtime 总是一起安装。
SDK 的版本,仅仅是一个版本号,不同的版本之间,不具有本质的区别。版本号仅仅表示这个 SDK 支持到哪一个版本的内容。因此,我们可以从当前的 SDK 版本构建任何以前的版本,而不仅仅是当前安装的 SDK 版本。
这个话说起来有点绕,举个例子,我的机器上只装了 Dotnet Core 5.0 SDK,我也可以构建 Dotnet Core 2.0 的应用,而不需要非得装 Dotnet Core SDK 2.0。
当我们 SDK 来构建应用时,SDK 会根据构建的版本,来下载适当的引用包。这些包包含构建应用所需要的占位符、元数据和程序集。而编译系统会根据这些引用程序集来编译代码,以生成应用程序。
所以,实际在开发环境中,只需要安装最新版本的 SDK,就可以了。
运行时则不一样。在早期 Dotnet Framework 系列时,框架是向后兼容的,Framework 4.5 的框架完全可以运行 Framework 2.0 的应用程序。但到了 Dotnet Core,就不一样了,它被明确的版本所定义和区别。旧版本编译的程序,在高版本的运行时上,不一定能正常运行。
所以,如果你装了一堆 SDK 和 Runtime,你其实可以这样清理:SDK 保留最新的版本,Runtime 保留各个主版本中最新的版本。好在,各个版本仅以目录的形式存在,清理起来很简单。
总结
Dotnet Core 跨框架运行是一个很复杂的内容,如果你从头去翻微软的文档,那会很头大。
因此,我这个文章,用尽量简单的方式,给大家入个门。
喜欢就来个三连,让更多人因你而受益