惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
量子位
V
V2EX
S
SegmentFault 最新的问题
月光博客
月光博客
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
博客园_首页
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
Y
Y Combinator Blog
The Cloudflare Blog
C
Check Point Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
腾讯CDC
B
Blog
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角
从 .NET Core 2.2 升级到 3.1 的踩坑之旅 - 元视角
飞鸿踏雪 · 2020-01-22 · via 元视角

有时候,版本更新太快并不是一件好事。虽然,两周一个迭代的“敏捷”开发依然被客户嫌弃交付缓慢,可一边是前端领域“求不要再更新了,学不动了”的声音,一边则是.NET Core从1.x到2.x再到3.x的高歌猛进。版本更新太快,带来的是API的频繁变动,无法形成有效的知识沉淀,就像转眼到了2020年,Python 2.xWindows 7都引来了“寿终正寝”,可能你都还没有认真地学习过这些知识,突然就被告知这些知识要过期了,想想还是觉得挺疯狂啊。最近一直在捣鼓,如何让.NET Core应用跑在Heroku平台上,因为Docker镜像里使用最新的.NET Core 3.1运行时,所以,痛定思痛之余,决定把手头项目升级到3.1。上一次痛苦还是在2.1升级2.2,这还真没过多长时间。所以呢,这篇博客主要梳理下从2.2升级到3.1过程中遇到的问题。

更新项目文件

  • 调整目标框架为netcoreapp3.1
  • 删除引用项:Microsoft.AspNetCore.AppMicrosoft.AspNetCore.Razor.Design
  • 删除AspNetCoreHostingModel,如果项目文件中的值为InProcess(因为ASP.NET Core 3.0 或更高版本项目默认为进程内承载模型)

更新程序入口

  • CreateWebHostBuilder()方法的返回值类型由IWebHostBuilder调整为IHostBuilder
  • 增加引用项:Microsoft.Extensions.Hosting
  • Kestrel配置变更至ConfigureWebHostDefaults()方法
public static IHostBuilder CreateWebHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.ConfigureKestrel(serverOptions =>
             {
                    // Set properties and call methods on options
             })
             .UseStartup<Startup>();
        });

如果通过 HostBuilder手动创建宿主,则需要在 ConfigureWebHostDefaults()方法中显式调用·UseKestrel()

public static void Main (string[] args) 
{
    var host = new HostBuilder ()
        .UseContentRoot (Directory.GetCurrentDirectory ())
        .ConfigureWebHostDefaults (webBuilder => 
        {
            webBuilder.UseKestrel (serverOptions => 
            {
                // Set properties and call methods on options
            })
            .UseIISIntegration ()
            .UseStartup<Startup> ();
        })
        .Build ();

    host.Run ();
}

更新Startup

  • Configure()方法第二个参数由``IHostingEnvironment调整为IWebHostEnvironment(需要引用Microsoft.Extensions.Hosting`)
  • 从管道中删除UseMvc()扩展方法,相应地,删除AddMvc()及其链式调用相关方法
  • AddMvc()等价于AddRazorPages() + AddControllersWithViews()
  • AddControllers()对应WebApi模板,AddControllersWithViews()对应MVC模板, AddRazorPages()对应SPA模板
  • 路由注册由传统路由调整为终结点路由
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
         //SignalR路由      
        endpoints.MapHub<ChatHub>("/chat");
        //RazorPages路由
        endpoints.MapRazorPages()
        //特性路由(WebApi)
        endpoints.MapControllers();
        //控制器路由(MVC)
        endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

如果希望继续使用传统路由,则可以使用下列方法任一:

services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddControllers(options => options.EnableEndpointRouting = false);
services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);

序列化/反序列化

  • .NET Core 3.0 开始,System.Text.Json默认作为替代Newtonsoft.json的新一代JSON API
  • 直接从.NET Core 3.0 创建的SignalR项目,服务端返回的JSON数据存在大小写的问题,这是由System.Text.Json引起的。解决方案是:
services.AddSignalR()
    .AddJsonProtocol(options => options.PayloadSerializerOptions.PropertyNamingPolicy = null);

同理,对于该方案对于services.AddControllers()一样有效,前提是项目中使用了System.Text.Json。同理,对于SignalR的客户端项目,我们有:

new HubConnectionBuilder()
    .WithUrl("/chatHub")
    .AddJsonProtocol(options =>
    {    
        //TODO
    })
    .Build();
  • SignalR的JavaScript客户端由@aspnet/signalr 调整为为 @microsoft/signalr
const signalR = require("@microsoft/signalr");
let connection = new signalR.HubConnectionBuilder().withUrl(url).build();
  • 如果希望继续使用Newtonsoft.json,则需要安装AspNetCore NewtonsoftJson。相应地,需要显式调用AddNewtonsoftJson()扩展方法:
services.AddControllers()
    .AddNewtonsoftJson(options => 
    {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    });

同样地,AddNewtonsoftJson()支持AddControllers()AddControllersWithViews()AddRazorPages()所有方法

疑难杂症

  • 升级后提示无法加载类型:Microsoft.AspNetCore.Mvc.MvcJsonOptions,解决方案是: 升级Swashbuckle.AspNetCore至最新版本(5.0+),调整Swagger中间件配置代码:
services.AddSwaggerGen(swagger =>
{
    //这里发生了变化,需要引用:Microsoft.OpenApi.Models
    swagger.SwaggerDoc("v1", new OpenApiInfo { Title = "ynamic WebApi", Version = "v1.0" });
});
  • 安装完 .NET Core 3.x,使用dotnet build编译项目提示找不到Microsoft.NET.Sdk.Web。解决方案是: 升级2.2的时候,调整项目文件中的Microsoft.NET.Sdk.WebMicrosoft.NET.Sdk可以解决,而这个方法在3.x以后失效。 此时,可以检查环境变量MSBuildSDKsPath中的SDK版本和实际版本是否一致,尤其是像博主这样从2.0一路升级到3.x的朋友,应该都会遇到这个问题。

参考链接