.NET Core 2.1 迁移至 3.1 踩坑记录
首先,第一个大坑也是迁移到3.1到最后已经No Error才发现的:
这个2012 R2+可不是写着玩的,是真的必须升级数据库!
好,接着讲其它的坑:
当你把Visual Studio 2019升级到16.6.2的时候,你的nuget包管理器就装不上任何包了,会一直报错,
Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION)
至少在我的项目里面是这样的。
其实,我也不是第一个遇到这个问题的,这个问题早在5月1号就提出过,到今天6月20号社区给出的一个解决方案是回退版本。
实际上,这个修复影响并不大,因为用Powershell照样可以安装包的。只是IDE上的nuget管理器用不起来了而已。
例如:
Install-Package Microsoft.AspNetCore.Identity.UI
如何从2.1向3.1迁移:
1.修改目标框架
<!--<TargetFramework>netcoreapp2.1</TargetFramework>-->
<TargetFramework>netcoreapp3.1</TargetFramework>
并去除
<PackageReference Include="Microsoft.AspNetCore.App" />
2. 升级依赖的NuGet包
update-package <package_name>
3.startup.cs文件
IHostingEnvironment 已过时, 要修改为IWebHostEnvironment
去除app.UseDatabaseErrorPage();
将
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "{controller=MainPage}/{action=Index}/{id?}");
//});
改成:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name:"default",
pattern: "{controller=MainPage}/{action=Index}/{id?}"
);
});
……
其它的按照ERROR提示,一步一步nuget包装好,装对,基本没有太大问题。
最后,回顾一下大坑:
b => b.UseRowNumberForPaging()
如果你尝试在上下文DBContext的连接SQL Server的字符串后面写这个,就一定会有绿线标记。
这个方法,并没有完全被标记为弃置,但已经没任何用了。
这个方法是用来照顾SQL Server 2008的使用者的,但是.NET Core 3.0版本之后,表示不再支持UseRowNumberForPaging()。
你不能在前台的Razor页面里面用Take()或者Skip()方法,因为在旧版数据库中,这意味着使用关键字FETCH NEXT……
要么继续呆在.NET Core 2.1,要么升级数据库。
微软官方的意思是不再维护这个方法了,甚至不打算出替代方案。
我选择了升级数据库:
- 检查版本号,我的版本号是10.50.4000.0,是SP2版本。
- 查看官方文档提供的升级路径
- 得知我的SP2版本要先升级到SP3,再升级到Express
- 10.50.4000.0->10.50.6000.34 Microsoft® SQL Server® 2008 R2 的 Service Pack 3
- 最后用SQL Server 2016的完整安装包安装
- 注意你下载到的将会是2016 SP2的下载器,选择Advanced下载完整文件。
然后升级完成之后,会发现UI没换:
但点开属性,可以发现版本以为13.0,原版本是10.50.4000.0。
别着急,尽管这样,还会报错:
There is already an open DataReader associated with this Command which must be closed first.
这个是3.1的特性,为了提高安全性,防止内存泄漏,防止注入……
直接的解决方案是在连接字符串后面增加MultipleActiveResultSets=true;
其实在写代码的阶段的时候尽量就应该注意避免打开多个DataReader,但是因为我的是个人博客,不太需要在乎这些事情。
接着是用数据字典+LINQ产生的Error:
InvalidOperationException: The LINQ expression could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
你惊讶的发现,你的Linq语句没有被translated,虽然检测语法通过,但最终还是抛出了异常。
这个是.NET Core 3.0版本之后,通过评估性能,而拒绝掉的一些linq特性,因为这样的Linq可能会造成服务器性能下降。
如果你用了GroupBy那就得更加注意了,这是详细的解决方案:
我的理解是,不要GroupBy,想办法换成其它的。所以我尝试在GroupBy之前加了AsEnumerable()。(但实际上你得重构代码)
接着又报另一个错误:
OFFSET”附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效
这个主要是在sql server 2008中,不支持FETCH和NEXT语句(sql server 2012才支持)(但是我已经换到2016了啊)
原因猜测:
尽管从PowerShell里面看到SQL Server的Vesion已经升级到13.x,但是在执行语句的标准上,看起来好像还是按照2008R2的来的。
于是我直接卸载了SQL Server 2008 R2 Express和SQL Server 2016 SP2 Express,直接重新安装SQL Server 2017 Express。(完全卸载SQL Server和安装SQL Server折腾了不少时间)
最后,总算是解决了FETCH NEXT语句的问题。总的来说,数据库安装真的是费了不少精力,我一度甚至想重装系统,后来想到,去拿阿里云服务器测试,装坏了就重开镜像,方便了很多,终于是试完了解决了问题。
附录:
https://docs.microsoft.com/zh-cn/aspnet/core/migration/30-to-31
https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30
https://docs.microsoft.com/zh-cn/aspnet/core/migration/21-to-22
SQL Server相关:
[2] SqlServer 2008R2 10.50.1600.1 升级到 SqlServer 2016
Exception from HRESULT: 0x80020009相关:
[1] Introduce the ability to roll back a Visual Studio Update
[2] Exception occurred. (Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION))
[3] Exception occurred. (Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION)) #6177