将 ASP.NET Core 2.1 升级到最新的长期支持版本ASP.NET Core 3.1
目录
- 前言
- Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 消失了
- 升级到 ASP.NET Core 3.1
- ViewBag 与 Razor Pages 第一次接触
- ViewBag 与 Razor Pages 第二次接触
- 小结(文件更改对比图)
- ASP.NET Core 3.1的确很棒,肉眼可见的快、快、快!
前言
2019年的最后一个月,微软终于发布了.Net Core 3.1,这是 .Net Core 有史以来的第二个长期支持版本(至少 3 年的支持期限)。
作为一个大版本更新,.NET Core 3.0 引入了大量改进和新特性,例如新增加的 Windows Forms 和 WPF、新的 JSON API、对 ARM64 架构的支持,以及全面提升的性能。
所以升级是势在必行的,那么很多开发人员就面临一个问题:
如果从上一个长期支持版本 ASP.NET Core 2.1 升级到最新的 ASP.NET Core 3.1 ?
.Net Core 版本列表:
From:https://dotnet.microsoft.com/download/dotnet-core
如果是之前的 .Net Framework,这个升级是非常平滑的,甚至不需要做任何改动(比如:.Net Framework 2.0 -> .Net Framework 4.5),但是 .Net Core 的升级却有点麻烦,微软给出了一系列的升级指南,不过都是从上一个版本到下一个紧邻版本:
ASP.NET Core 2.1 -> 2.2:https://docs.microsoft.com/zh-cn/aspnet/core/migration/21-to-22
ASP.NET Core 2.2 -> 3.0:https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30
ASP.NET Core 3.0 -> 3.1:https://docs.microsoft.com/zh-cn/aspnet/core/migration/30-to-31
当然这个过程不仅仅是改个配置文件的问题,.Net Core 的版本升级中居然有很多 Breaking changes,也就是说如果你用的类在 .Net Core 3.1 中突然删除了,对不起,你只有调整自己代码的份了。
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 消失了
而且这个 Breaking changes 还不少,比如 FineUICore 之前的版本(支持ASP.NET Core 2.1)用到的 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 在 .Net Core 3.1 就被无情的删掉了:
那位说了,你为啥要用 .Internal 里面的类?
这是很正常的,FineUICore作为一个支持 ASP.NET Core 的控件库,需要一些底层操作,为了支持快速数据绑定,类似如下的形式:
- 支持 TagHelpers 的页面代码:<f:DatePicker For="TheModel.StartDate"></f:DatePicker>
- 支持 HtmlHelpers 的视图代码:F.DatePickerFor(m => m.TheModel.StartDate)
可以参考示例:https://pages.fineui.com/#/DataModel/UICompare
为了支持这个特性,我们就需要计算表达式的文本值,以及表达式所绑定的数据,因此就用到了如下两个静态类方法:
- ExpressionHelper.GetExpressionText
- ExpressionMetadataProvider.FromLambdaExpression
在 .Net Core 2.2 之前的版本,这两个方法是逃不过的。可惜不巧的是,微软却认为这些方法没有公开的价值,因此就武断的隐藏掉了(你让之前使用这些类的程序情何以堪!)。
网络上有很多类似的提问,但是阻挡不了微软隐藏几乎所有 .Internal 命名空间类的做法。
https://github.com/aspnet/AspNetCore/issues/8678
https://github.com/aspnet/Mvc/issues/8724
在 ASP.NET Core 3.1 虽然有替代的方法可以实现上述被删掉的功能,但是就做不到向后兼容了。FineUICore近期已经升级到 FineUICore v6.2.0,以便适用这个改动,升级之后支持 .Net Core 3.1+,不再对老版本提供支持了。
升级到 ASP.NET Core 3.1
下面我们会以 FineUICore.Examples 为例,讲解如果将 ASP.NET Core 2.1 升级到 ASP.NET Core 3.1,这里面的坑还真不少。
项目文件(.csproj)
这里面有几点需要注意:
1. TargetFramework 改为 netcoreapp3.1
2. 删除 Microsoft.AspNetCore.App 的引用,这个会默认包含在框架 Sdk=Microsoft.NET.Sdk.Web 中
3. 添加 Microsoft.AspNetCore.Mvc.NewtonsoftJson 的引用
有一点需要特别注意, .Net Core 3.0 已经从共享框架中删除了 Newtonsoft.Json,并引入新的 System.Text.Json 类库。
但是我们的 FineUICore 示例代码很多地方都依赖了 Newtonsoft.Json 的特性,因此需要引入 Microsoft.AspNetCore.Mvc.NewtonsoftJson,这个引用会自动包含 Newtonsoft.Json 库,可以求证于编译时的 Debug 文件夹,位于项目的 \bin\Debug\netcoreapp3.1:
完整的项目工程文件:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
</ItemGroup> <ItemGroup>
<ProjectReference Include="..\FineUICore\FineUICore.csproj" />
</ItemGroup> </Project>
Program.cs
需要注意的几点:
1. 将 IWebHostBuilder 改为 IHostBuilder
2. 将 Web 服务器的启动代码放到 ConfigureWebHostDefaults 中
当然,这些改动我们不需要特别关心,简单的照做就行了。
完整的 Progam.cs 代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; namespace FineUICore.Examples
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Startup.cs
这里的改动有点多,我们分两个截图分别说明 ConfigureServices 和 Configure 的改动:
这里有几点需要调整:
1. 用 AddControllersWithViews 替代 AddMvc
2. 对参数 ModelBinderProviders 更改放到 AddMvcOptions 中
3. 添加 AddNewtonsoftJson 用来使用老的 Newtonsoft.Json 来序列化 JSON 数据
ASP.NET Core 3.1 添加了三个新的服务注册方法来代替之前的 AddMvc:
- AddRazorPages:添加对 Razor Pages 的支持
- AddControllersWithViews:添加对控制器和视图的支持
- AddControllers:添加对控制器的支持
这些方法可以组合,比如如下代码等效于之前版本的 AddMvc:
services.AddControllersWithViews();
services.AddRazorPages();
这个方法的完整代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddSession(); // 配置请求参数限制
services.Configure<FormOptions>(x =>
{
x.ValueCountLimit = ; // 请求参数的个数限制(默认值:1024)
x.ValueLengthLimit = ; // 单个请求参数值的长度限制(默认值:4194304 = 1024 * 1024 * 4)
}); // FineUI 服务
services.AddFineUI(Configuration); services.AddControllersWithViews().AddMvcOptions(options =>
{
// 自定义模型绑定(Newtonsoft.Json)
options.ModelBinderProviders.Insert(, new JsonModelBinderProvider());
}).AddNewtonsoftJson();
}
下面来看下 Configure 方法:
这里面有几点重要改动:
1. 将 IHostingEnvironment 改为 IWebHostEnvironment
2. 添加 app.UseRouting();app.UseAuthorization();,注意添加的位置,要放到 UseStaticFiles 的后面
3. UseMvc 改为 UseEndpoints
完整的函数代码:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSession(); app.UseRouting(); app.UseAuthorization(); // FineUI 中间件(确保 UseFineUI 位于 UseEndpoints 的前面)
app.UseFineUI(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "area",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
}); }
对于支持 Razor Pages 的项目,这里的 UseEndpoints 代码要改为:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
ViewBag 与 Razor Pages 第一次接触
在传统的 Controller/Model/View 的 MVC 架构中,我们可以在控制器中使用 ViewBag 将数据传递到 视图中,虽然 ViewBag 只是字典类 ViewData 的一个动态封装,但是写法更简单:
然而在 Razor Pages 的页面模型类中,却少了对 ViewBag 的支持,因此在 ASP.NET Core 2.2 之前的版本里,我们通过在基类中新增一个 ViewBag 属性来解决:
可以看出,这里的 ViewBag 其实是一个 dynamic 类型,内部存储单元还是 ViewData,这段代码来自:https://forums.asp.net/t/2128012.aspx?Razor+Pages+ViewBag+has+gone+
这么一个看似很技巧的东西其实来自微软某位程序员的自(zi)信(da),如果你留意观察,就会发现一个奇怪的逻辑:
- Controller 基类 和 View 视图中支持 ViewBag
- Razor Pages的后台模型类中不支持 ViewBag,然后 Razor Pages的页面中支持 ViewBag
说白了,微软的逻辑是:你可以在 Razor Pages 中使用 ViewBag(尽管也可以设置) ,但是别在模型类中设置 ViewBag。
这位大虾(DamianEdwards)在一个 Github 的 issue 中提到这样一个观点:
We purposefully didn't add ViewBag because I wanted to discourage its use. As @pranavkm points out you can add it back easily enough if you wish but I don't have plans to add it back to the built-in base class.
原文:https://github.com/aspnet/Mvc/issues/6754
我带点感情色彩的翻译一下哈:
我就看 ViewBag 不顺眼了,所以故意不添加 ViewBag。并且我也不准备在以后的版本中把 ViewBag 加回来,你非要用的话自己弄吧!
在另一个回复中,DamianEdwards提到了 ViewBag 可能有性能问题:
ViewBag uses dynamic which in our testing introduces a measurable performance impact on the processing of pages or views that use it.
不过,这个决定权不能留给用户自己吗?如果我只是想通过 ViewBag 传递两三个数据,绝对不会遇到什么性能问题,并且这应该是 90% 的应用场景。
最终,吐槽归吐槽,代码是你写的,你想咋搞就咋搞。
ViewBag 与 Razor Pages 第二次接触
然而,在升级到 ASP.NET Core 3.1 之后,这个地方又报错了。
原因我们前面提过,对 ViewBag 的封装用到了 DynamicViewData,这个类是定义在 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 里面的。而在 ASP.NET Core 3.1 中,微软删除 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 的公开访问权限。
在实际项目中,我们还是要遵循微软的建议,使用 ViewData 而不是 ViewBag。
然而我们的 FineUICore 示例项目有 750 多个页面,很多地方都用到了 ViewBag,为了和之前的版本兼容,我们还是要把 ViewBag 找回来。
既然 DymaicViewData 不见了,就自己创建一个 DymaicViewData:
public class DynamicViewData : DynamicObject
{
private ViewDataDictionary ViewData; public DynamicViewData(ViewDataDictionary viewData)
{
ViewData = viewData;
} /// <summary>
/// 获取所有key
/// </summary>
public override IEnumerable<string> GetDynamicMemberNames()
{
return ViewData.Keys;
} /// <summary>
/// 调用 ViewBag.key; 时执行
/// </summary>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
return true;
} /// <summary>
/// 调用 ViewBag.key = "value"; 时执行
/// </summary>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
ViewData[binder.Name] = value;
return true;
}
}
在后台模型类基类中,调用方法改为:
private DynamicViewData _viewBag; public dynamic ViewBag
{
get
{
if (_viewBag == null)
{
_viewBag = new DynamicViewData(ViewData);
}
return _viewBag;
}
}
小结(文件改动对比图)
综上所述,升级到 ASP.NET Core 3.1 主要改动三个项目文件,其他地方基本没有变化。
为了更直观的查看这三个文件的改动,我们做了下面三幅对比图片(以FineUICore.EmptyProject项目为例)。
注:下面截图中的 ASP.NET Core 2.1 和 ASP.NET Core 3.1 刚好标反了,阅读时请注意区分。
1. 项目工程文件(FineUICore.EmptyProject.csproj)
2. Program.cs
3. Startup.cs
注:上面截图中的 ASP.NET Core 2.1 和 ASP.NET Core 3.1 刚好标反了,阅读时请注意区分。
ASP.NET Core 3.1的确很棒,肉眼可见的快、快、快!
刚把 FineUICore 的官网示例部署到服务器时,管理员是这么给我说的:
之前一直没有注意,看来 ASP.NET Core 的性能的确是要好一些。
我对比了 FineUIPro(WebForms) 和 FineUICore(ASP.NET Core) 的在线示例网站,发现 ASP.NET Core 3.1 的确比 WebForms 快多了。
肉眼可见的快、快、快,下面两个动画图片可见一斑:
【ASP.NET WebForms】https://pro.fineui.com/
【ASP.NET Core 3.1】https://core.fineui.com/
这两个站点部署在同一台服务器的同一个IIS里面,为了便于区分,FineUICore(ASP.NET Core)为深色主题,FineUIPro(WebForms)为浅色主题。
注:由于是共享服务器,所以服务器资源在不同时刻会有变化,并且网络环境也是不断变化的,可以在同一时刻(测试间隔小于1s)多次测试两个网站。
当然每个人测出来的结果会不尽相同,欢迎分享你的测试截图....
延伸阅读:
【推荐】全新ASP.NET Core,比WebForms还简单!
ASP.NET Core 快速入门(FineUICore + Razor Pages + Entity Framework Core)
完整的FineUICore(基础版)和示例网站源代码请到加入我的圈子下载:https://fineui.com/fans/
将 ASP.NET Core 2.1 升级到最新的长期支持版本ASP.NET Core 3.1的更多相关文章
- centos7.6环境zabbix3.2源码编译安装版升级到zabbix4.0长期支持版
zabbix3.2源码编译安装版升级到zabbix4.0长期支持版 项目需求: .2版本不再支持,想升级成4.0的长期支持版 环境介绍: zabbix服务端是编译安装的,数据库和web在一台机器上 整 ...
- 翻译 - ASP.NET Core 托管和部署 - 在 Linux 上使用 Nginx 托管 ASP.NET Core 网站
翻译自 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-5.0 本文介 ...
- CentOS6下用yum升级系统最新内核版本
首先当你决定升级内核时,要想清楚为什么升级内核,因为升级内核会带来很多麻烦.所以这种事情能避免就避免 导入 Public Key rpm --import https://www.elrepo.org ...
- 一行命令将ubuntu升级到最新版本
zzupdate 是一个开源的命令行程序,通过将几个更新命令组合到一个命令中,使得将 Ubuntu 桌面和服务器版本升级到更新版本的任务变得容易一些. 将 Ubuntu 系统升级到更新的版本并不是一项 ...
- ASP.NET 5运行时升级到Beta5
在Visual Studio 2015 RTM和Windows 10正式发布之前,微软把开源.NET升级到了beta5,带来了一些增强和改变.和Visual Studio 2015 RC一起安装的AS ...
- vs2015 已经支持开发asp .net core 1.0 rc2 程序了
vs2015 已经支持开发asp .net core 1.0 rc2 程序了 http://mp.weixin.qq.com/s?__biz=MzI0MzM1ODczOQ==&mid=2247 ...
- ASP.NET 5探险(4):如何把ASP.NET 5从beta4升级到beta5
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:上一篇文章讲述了ASP.NET 5 Beta带来的一些变化,虽然原文最后给出了从bet ...
- 《ASP.NET Core In Action》读书笔记系列二 ASP.NET Core 能用于什么样的应用,什么时候选择ASP.NET Core
ASP.NET Core 能用于什么样的应用 ASP.NET Core 可以用作传统的web服务.RESTful服务.远程过程调用(RPC)服务.微服务,这归功于它的跨平台支持和轻量级设计.如下图所示 ...
- .Net Core 2.1 升级3.1 问题整理
随着技术的不断拓展更新,我们所使用的技术也在不断地升级优化,项目的框架也在不断地升级,本次讲解 .net core 2.1 升级到3.1所需要注意的事项: 当项目框架升级后,所有的Nuget引用也会 ...
随机推荐
- 归一化 (Normalization)、标准化 (Standardization)和中心化/零均值化 (Zero-centered)
博主学习的源头,感谢!https://www.jianshu.com/p/95a8f035c86c 归一化 (Normalization).标准化 (Standardization)和中心化/零均值化 ...
- 20191102Java课堂记录
1. import javax.swing.*; class AboutException { public static void main(String[] a) { int i=1, j=0, ...
- LeetCode 第98题--验证二叉搜索树
1. 题目 2.题目分析与思路 3.代码 1. 题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当 ...
- 如何学习理解Redux Middleware
Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会.可以允许我们添加自己的逻辑在这段当中.它提供的是位于 action 被发起之后 ...
- 通过示例学习rholang(上部:课程0-6)
通过例子和实践来学习rho语言.下面的例子和练习都很值得去运行.阅读.修改和完善.修改练习和教程中任何你感到有意思的代码,这样能够获得最好的学习效果.该教程包含了rho语言最常见以及最重要的特性,足以 ...
- 深入理解Java虚拟机:JVM高级特性与最佳实践
第一部分走近Java第1章走近Java21.1概述21.2Java技术体系31.3Java发展史51.4Java虚拟机发展史91.4.1SunClassicExactVM91.4.2SunHotSpo ...
- python 获取网页图片 十月底的 一弹
#!/usr/bin/pythonimport reimport urllib def getHtml(url): page=urllib.urlopen(url) html=page.r ...
- 2019杭电多校赛第九场 Rikka with Mista
Problem Description Rikka is a fervent fan of JoJo's Bizarre Adventure. As the last episode of Golde ...
- Python中类属性和实例属性的区别
在Python中经常会混淆类属性和实例属性的概念,今天专门记录一下个人理解以免日后忘记. 看下面的例子: class Tencent(): i = 10 # 此处i为类属性 def __init__( ...
- TypeScript——基本类型
关于数据类型 原始类型 let bool: boolean = true; let num: number = 1; let str: string = 'i am string'; 引用类型 let ...