目录
1. builder.UseMySql(string)不再存在。
2. IMutableProperty中缺少Relational()
10. CorsAuthorizationFilterFactory缺失
没坏就不用修了?
我想必须问的第一个问题是,只要应用程序正常工作,为什么还要进行升级呢?这是一个很好的问题,有几个原因:
- 从现在开始发布的任何新代码示例或包都可能针对较新的.NET版本,因此如果我们也使用最新的.NET版本,我们可能会更轻松地集成它们。
- .NET 2.1已于2021年8月终止支持。这意味着添加到较新.NET版本的任何改进都不会向后移植到2.1。FOMO多吗?
- 如果您在云中运行.NET应用程序(例如:AWS Lambda),您的云提供商可能会强制您升级。
- 据报道,.NET 6比以前的版本快得多。
我应该升级到哪个版本?
我认为这是一个非常好的问题,因为在任何给定时间通常至少有2-3个合理的选择。我可能会建议查看当前支持的.NET版本,记下每个版本何时会终止支持,然后做出相应决定。我通常会在可能的情况下选择LTS(长期支持)选项,因此希望几年内我不必担心再次升级。目前,最新的LTS版本是 .NET 6,支持到2024年11月。
安装.NET 6
首先,让我们看看您当前是否在您的机器上安装了.NET 6 SDK。一个简单的方法是在您喜欢的终端中运行以下命令:
dotnet --list-sdks
如果您没有看到.NET 6的条目,则需要安装它。您可以使用Visual Studio执行此操作,但以防万一您碰巧使用不同的代码编辑器或IDE(也许是vim?),这里有一个链接,您可以直接从该链接下载安装程序。
安装新的SDK后,前面的命令现在应该包含6.0.101(或您刚刚安装的任何版本)。
升级项目
安装SDK后,下一步是更新我们TargetFramework的每个csproj文件。如果您从.NET Core 2.1迁移,这可能会设置为netcoreapp2.1。在每个项目中将其更改为:
<TargetFramework>net6.0</TargetFramework>
保存后,您很可能会遇到1000个错误,并且您的解决方案中的每个文件都将被授予荣誉的红色波浪下划线。要解决这些问题,我们首先需要将您的解决方案包升级到与.NET 6兼容的版本。
升级解决方案
如果您的解决方案中有global.json文件,则需要升级该sdk属性。例如:
"sdk": {
"version": "6.0.0"
}
您可以在此处阅读更多global.json 信息。本质上,此值仅用于CLI工具,但将其设置为与项目本身定义的版本相同是有意义的。
升级包
如果您使用的是Visual Studio(或Rider),请右键单击您的解决方案并单击Manage nuget packages。具体来说,我们对有可用更新的软件包感兴趣。您可以尝试从Microsoft软件包开始一次升级这些,或者您可以只使用它并立即升级所有内容,并处理升级后出现的任何问题。由您决定如何处理这一步。由于这只是一个爱好项目,我只是一次升级了所有软件包。
在IDE中升级MSBuild版本
此步骤可能仅适用于Rider用户。就我而言,我需要在Preferences -> Toolset下升级我的MSBuild目录并按照此处所述进行构建。您可能希望选择具有最高MSBuild版本的目录。Visual Studio用户可能可以跳过这一步。
完成这一步后,我注意到我的绝大多数错误都消失了。请注意,您可能还需要清理和重建您的解决方案。
Microsoft.AspNetCore.App警告
Microsoft.NET.Sdk.DefaultItems.Shared.targets(111, 5): [NETSDK1080] A PackageReference to Microsoft.AspNetCore.App is not necessary when targeting .NET Core 3.0 or higher. If Microsoft.NET.Sdk.Web is used, the shared framework will be referenced automatically. Otherwise, the PackageReference should be replaced with a FrameworkReference.
这更像是一个警告而不是错误,但解决这个问题仍然很好。找到任何现有的包引用Microsoft.AspNetCore.App并将其删除,因为它现在是多余的。这可能会出现在您的顶级API项目中。
实体框架重大更改
1. builder.UseMySql(string)不再存在。
这可能会或可能不会影响其他SQL变体,但DbContextOptionsBuilder上的UseMysql(string)扩展方法现在需要第二个参数,它指定服务器版本。一个简单的解决方法就是让项目再次编译是自动检测版本。例如:builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));。
2. IMutableProperty中缺少Relational()
如果您正在设置显式数据库列类型(例如十进制精度),您可能已经注意到Relational()已经从IMutableProperty中消失了。您可以用调用SetColumnType(string)来替换它。
3.String.Format不能翻译成SQL
在.NET Core 2.1中,我有一些LINQ-To-SQL查询,如下所示:
await _dbContext.SomeDbSet
.Where(a => a.SomeID == id)
.Select(a => new
{
a.SomeID,
// ...
Name = a.NavigationProperty == null ?
"" :
$"{a.NavigationProperty.FirstName} {a.NavigationProperty.LastName}"
在.NET 6(或其他地方)中,这不再受支持,因此我需要在返回查询结果后检索这两个值并在代码中执行串联。
4. 无法返回嵌套查询
我有一个看起来像这样的数据结构:
private class ListItemsQuery
{
public Item Item { get; set; }
public IQueryable<SubItem> SubItems { get; set; }
}
在.NET Core 2.1中,我能够返回一个本身包含一个IQueryable<SubItem>属性的IQueryable<ListItemsQuery>值。但在.NET 6中,这会产生以下结果:
The query contains a projection '<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.a' of type 'IQueryable<SubItem>'. Collections in the final projection must be an 'IEnumerable<T>' type such as 'List<T>'. Consider using 'ToList' or some other mechanism to convert the 'IQueryable<T>' or 'IOrderedEnumerable<T>' into an 'IEnumerable<T>'.
将嵌套的IQueryable更改为List效果很好——尽管这意味着查询的一部分确实需要比以前更早地实现。还有一些其他复杂的LINQ查询也需要修复。
大摇大摆的改变
5. 无法解析符号信息
只需更改为OpenApiInfo。
6. 无法解析符号ApiKeyScheme
只需更改为OpenApiSecurityScheme。但是,In和Type属性也有重大变化。
In以前是字符串,现在是ParameterLocation类型。 用ParameterLocation.Header替换"header"字符串。Type以前也是一个字符串,现在是SecuritySchemeType类型。 将之前的字符串替换为SecuritySchemeType.Http, 或其他适当的值。
7. DocExpansion签名变更
这从字符串更改为DocExpansion枚举值。
8. SwaggerResponse属性缺失
这可以简单地替换为ProducesResponseType。
9. SwaggerOperation属性缺失
基本上,所有Swagger特定的属性都被提取到Swashbuckle.AspNetCore.Annotations中。通常,这些不是必需的,您可以只使用.NET Core属性(如ProducesResponseType),但如果您愿意,可以安装swashbuckle注释包。
启动重大更改
10. CorsAuthorizationFilterFactory缺失
我们可以简单地删除Mvc过滤器。
11. CORS政策变更
如果您使用的是非常开放的CorsPolicyBuilder策略,同时允许标头和凭据,您可能会收到类似于以下异常的内容:
Application startup exception: System.InvalidOperationException: The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the CORS policy by listing individual origins if credentials needs to be supported.
这可以通过删除调用AllowCredentials或调用AllowAnyOrigin来轻松解决,具体取决于您的情况。例如:
var corsBuilder = new CorsPolicyBuilder();
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin();
//corsBuilder.AllowCredentials();
12. IHostingEnvironment已过时
只需替换为IWebHostEnvironment。
13. MVC变化
替换AddMvc()为AddControllers()(假设您有一个API项目)。此处将更详细地讨论不同之处。
您还需要将您的app.UseMvc()行替换为:
app.UseRouting();
app.UseEndpoints(opts =>
{
opts.MapControllers();
});
这基本上是出于性能原因,以及与较新的代码示例和实践的一致性。UseRouting()必须出现在UseEndpoints()前面以避免启动时出现异常。
其他
14. 节点服务消失
看起来虽然很多开发人员都在使用NodeServices从C#调用自定义NodeJS逻辑,但其NodeServices的主要目实际上是用于从.NET API提供的SPA的SSR。由于大多数SPA的环境现在已更改为包含命令行工具(例如:Angular、React),NodeServices因此已被删除。此处将对此进行更详细的讨论。在这个阶段,NodeServices看起来最简单的替代品是名为Javascript.NodeJS的3rd-party包,尽管它似乎维护得很好。
你应该注入INodeJSService,而不是注入INodeServices。API非常相似,但内部确实有一些很大的不同。在我的例子中,我使用NodeJS库来呈现报告,所以我传入了一个HTML模板字符串并期望返回一个字节数组。这与Javascript.NodeJS的开箱即用效果不佳,因为它期望输入是JSON字符串。你可以让它工作,但它确实需要一些调整。
15. 不兼容的包
到目前为止,只有MSBump,尽管这已经被项目维护者存档了。
16.ServiceFilter堆栈溢出
与这篇文章非常相似,我之前使用服务过滤器来创建支持控制器依赖项的过滤器。根据微软的回复,他们建议实现一个IFilterFactory,但我发现只需ServiceFilterAttribute从属性实现中删除就可以解决问题。即 - 只需实现您的属性IAsyncAuthorizationFilter或IAsyncActionFilter根据需要,无需扩展ServiceFilterAttribute,这是 .NET Core 2.1 中推荐的方法(或至少在 2.1 中有效)。
17. 模型绑定
看起来数字不能再被隐式反序列化为字符串。例如,给定以下数据模型:
public class AddressModel
{
[StringLength(4)]
public string PostCode { get; set; } = "";
}
和以下有效载荷:
{ "postCode":2145 }
这将导致以下400响应:
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-9d782bbecbc2107262258e79a7df080e-8d29b1c98b0ea23e-00","errors":{"$.address.postCode":["The JSON value could not be converted to System.String. Path: $.address.postCode | LineNumber: 0 | BytePositionInLine: 151."]}}
这看起来像是.NET Core 3把Newtonsoft.Json换成System.Text.Json默认JSON序列化程序的副作用。安装Microsoft.AspNetCore.Mvc.NewtonsoftJson并添加AddNewtonsoftJson()到您现有的AddControllers()路由Startup::ConfigureServices()似乎可以解决此问题。如果您使用的是.NET Core 2.1,那么Newtonsoft.Json无论如何都是默认的JSON序列化器,因此无论如何保持一致可能是有意义的,以防止出现此类小问题。
无论如何,差不多就是这样!我花了大约一个小时进行升级,然后又花了几个小时来解决突然出现的问题。迄今为止,最大的突破性变化是节点服务的删除,但也有一些实体框架和JSON序列化变化值得关注。长话短说,升级本身并不需要很长时间——但您应该准备好花一些时间来捕捉和修复因升级而损坏的小东西。
您是否注意到.NET Core 2.1和.NET 6之间的其他任何破坏或显着变化?
本文最初发布于Upgrading from .NET Core 2.1 to .NET 6.0 - Jason's Blog
https://www.codeproject.com/Articles/5321164/Upgrading-from-NET-Core-2-1-to-NET-6-0