关于.NET Standard 2.0类库使用.NET 6.0抽象及宿主抽象包升级后跨版本兼容性的技术咨询
咱们针对你提出的四个问题,逐个梳理清楚:
问题1:能否在用于.NET Core 3.1的.NET Standard 2.0类库中使用.NET 6.0抽象?
答案是不行。虽然Microsoft.Extensions.Hosting.Abstractions 6.0.0标注了支持netstandard2.0,但ASP.NET Core的抽象组件和运行时版本是强绑定的。.NET Core 3.1应用运行时依赖的是该包的3.x版本,当你的类库编译时用了6.0.0版本的IStartupFilter,在3.1应用中运行时,CLR会因为程序集版本不同,把两个版本的IStartupFilter判定为完全不同的类型,直接导致类型转换异常。
问题2:升级后,MyStartupFilter在.NET Core 3.1应用中是否仍能正常工作?
基本没法正常工作。核心原因还是刚才说的程序集绑定冲突:3.1应用的DI容器里注册的是3.1.22版本的IStartupFilter,但你的类库实现的是6.0.0版本的接口,CLR会认为这两个类型不兼容,抛出类似“无法将类型MyStartupFilter转换为Microsoft.AspNetCore.Hosting.IStartupFilter”的异常。
你可能会想到用程序集绑定重定向强行把6.0.0版本映射到3.1.22,但这属于临时hack手段,很可能引发其他隐藏问题(比如接口内部实现的细微变化导致的逻辑异常),绝对不推荐在生产环境使用。
问题3:反过来,如果不升级该抽象包,能否在.NET 6应用中使用MyStartupFilter?
这个完全可以!.NET 6的运行时是向下兼容的,ASP.NET Core 6的IStartupFilter和3.1版本的接口签名完全一致,而且6.0版本的Microsoft.Extensions.Hosting.Abstractions包会兼容旧版本的接口类型。实际测试中,把依赖3.1.22抽象的类库放到.NET 6应用里,注册后能正常加载中间件,不会出现任何冲突。
问题4:是否上述两种情况都不可行,必须为类库配置多目标框架?
不是必须,但多目标框架是最稳妥、最专业的解决方案。如果你的类库只需要支持.NET Core 3.1和.NET 6,多目标可以让你针对每个版本使用对应的抽象包版本,从根源上避免程序集绑定冲突。
具体配置方法很简单,修改类库的.csproj文件:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <!-- 同时针对netstandard2.0和net6.0编译 --> <TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks> </PropertyGroup> <!-- 针对不同框架引用对应版本的包 --> <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' "> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.22" /> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' "> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" /> </ItemGroup> </Project>
这样编译后,类库会生成两个版本的输出:netstandard2.0版本适配.NET Core 3.1,net6.0版本适配.NET 6,完全贴合各自的运行时环境,没有任何兼容性问题。当然,如果你的类库逻辑非常简单,不涉及其他版本差异,只依赖3.1.22的抽象也能在6.0里正常运行,但多目标框架的扩展性更强,后续如果要添加版本专属功能会更方便。
内容的提问来源于stack exchange,提问作者Steven Liekens

