2.【.NET10 实战--孢子记账--产品智能化】--升级前的准备工作:项目依赖梳理与升级计划制定

我们在日常产品维护时,往往会遇到底层基础框架需要升级的情况,尤其是当底层框架升级到一个新的大版本时,可能会带来一些不兼容的变更,这时候我们就需要做好充分的准备工作,以确保升级过程顺利进行。从本文开始,我们将详细讲解如何将我们的产品从 .NET 8 升级到 .NET 10 。在正式升级之前,我们需要对项目的依赖关系进行全面梳理,包括第三方库的版本兼容性、NuGet 包的升级情况以及项目中使用的一些已废弃的 API 是否在新版本中被移除。与此同时,我们还需要制定一份详细的升级计划,明确升级的步骤、时间节点以及回滚方案,以便在升级过程中出现问题时能够快速恢复到原有状态。只有做好这些准备工作,才能最大程度地降低升级风险,确保项目在升级后能够正常运行。

一、确认环境

在升级之前,首先需要确认当前的开发环境是否满足 .NET 10 的要求。我们需要检查以下几个方面:

  • 操作系统:确保开发环境的操作系统版本支持 .NET 10,以下是最低操作系统版本和推荐操作系统版本。

    平台 最低支持版本 推荐版本
    Windows Windows 10 (1607) / Server 2016 Windows 11 / Server 2022+
    macOS macOS 12 (Monterey) macOS 15 (Sequoia)+
    Linux Ubuntu 20.04 / RHEL 8.10 / Debian 11 最新 LTS 版本 (如 Ubuntu 24.04)
  • 开发工具:确保使用的开发工具已经更新到支持 .NET 10 的版本。建议使用最新版本的 Visual Studio 2022 或更高版本,以获得最佳的开发体验和兼容性。

  • .NET SDK :安装 .NET 10 SDK,并确保环境变量配置正确。可以通过命令行运行 dotnet --version 来验证安装是否成功。

  • 安装 dotnet-outdated-tool:这是一个非常有用的工具,可以帮助我们检查项目中使用的 NuGet 包是否有更新版本,是否存在过时的包,特别是那些可能不兼容 .NET 10 的包。安装命令如下:

    shell 复制代码
    dotnet tool install --global dotnet-outdated-tool

以上这些环境确认步骤是升级前必须做的基础准备工作,确保开发环境与 .NET 10 的要求相匹配,可以避免在升级过程中遇到不必要的环境兼容性问题。

二、升级步骤

在这一小节,我们将详细讲解升级步骤,为后续的升级做准备。

2.1 基础框架升级

框架升级涉及到 10个 .csproj ,10个 Dockerfile 文件的修改,以及一些基础设施相关的配置文件的调整。我们需要将所有项目的目标框架(Target Framework)从 net8.0 修改为 net10.0,并且升级所有相关的 NuGet 包到支持 .NET 10 的版本。在这个过程中,我们可能会遇到一些破坏性变更(Breaking Changes),需要仔细阅读 .NET 10 的发布说明,了解哪些 API 已经被废弃或移除,并且根据需要修改代码以适应新的框架版本。下面这个检查列表可以帮助我们系统地完成升级:

  • 将所有 .csproj<TargetFramework>net8.0</TargetFramework> 改为 net10.0(10 个服务可并行修改)
  • 更新所有 Dockerfile 基础镜像:
    • mcr.microsoft.com/dotnet/sdk:8.0mcr.microsoft.com/dotnet/sdk:10.0
    • mcr.microsoft.com/dotnet/aspnet:8.0mcr.microsoft.com/dotnet/aspnet:10.0
  • 移除 SP.Common/SP.Common.csproj 中严重过时的 Microsoft.AspNetCore.Http.Abstractions 2.2.0(2018 年 ASP.NET Core 2.2 遗留包,.NET 10 框架已内置)
  • 从各服务 .csproj 中移除以下在 net10.0 框架内已内置的包:
    • System.Text.Json(出现在 SP.Common 等多个服务)
    • System.Text.Encodings.Web(出现在 IdentityService、FinanceService、ConfigService、NotificationService、ReportService 服务中)
2.2 微软官方包批量升级

这是一个低风险步骤,我们只需要将下表中包的版本升级到支持 .NET 10 的最新版本即可。可以使用 dotnet-outdated 工具来自动检查和升级这些包,确保它们与 .NET 10 兼容。

包名 当前版本 目标版本 涉及服务数
Microsoft.EntityFrameworkCore.*(所有子包) 8.0.8 10.0.x 8 个
Microsoft.AspNetCore.Identity.EntityFrameworkCore 8.0.8 10.0.x 6 个
Microsoft.AspNetCore.Authentication.JwtBearer 8.0.8 10.0.x ConfigService、IdentityService
Microsoft.Extensions.*(所有 Abstractions) 8.0.x 10.0.x SP.Common
System.Formats.Asn1 8.0.1 10.0.x 或移除 SP.Gateway
Microsoft.VisualStudio.Web.CodeGeneration.Design 8.0.7 10.0.x 6 个(开发工具)
Microsoft.Build 17.8.43 对齐 SDK 版本 6 个(开发工具)

同样,列出检查列表:

  • 批量执行包版本升级
  • Microsoft.EntityFrameworkCore.*(所有子包)
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.AspNetCore.Authentication.JwtBearer
  • Microsoft.Extensions.*(所有 Abstractions)
  • System.Formats.Asn1(升级到支持 .NET 10 的版本,或根据 .NET 10 的更新情况考虑移除)
  • Microsoft.VisualStudio.Web.CodeGeneration.Design(升级到支持 .NET 10 的版本)
  • Microsoft.Build(升级到与 .NET 10 SDK 版本对齐的版本)
2.3 EF Core + Pomelo MySQL

这一步属于中风险操作,我们要做的是将Pomelo.EntityFrameworkCore.MySql 8.0.3 包升级到 10.0.x 版本,以确保它与 EF Core 10 和 .NET 10 兼容,这个操作一共涉及八个微服务。在升级完后,我们还需要验证每个微服务的EF Core 的迁移历史是否能够正常应用到 MySQL 数据库中,确保数据访问层在升级后能够正常工作。以下是检查列表:

  • EF Core 官方包随 Phase 2 一同升到 10.0.x
  • Pomelo.EntityFrameworkCore.MySql 8.0.3 → 升到 10.0.x
    • Pomelo 版本号跟随 EF Core 而非 MySQL Server 版本
    • NuGet 上确认 10.0.x 可用
    • 涉及 8 个服务
  • 验证各服务 EF Core 迁移历史(EF 8 → 10 的迁移文件本身通常无需修改

Tip:Pomelo 版本号跟随 EF Core 的版本号而非 MySQL Server 版本号

2.4 认证与安全包

这一步也是中风险操作,我们需要升级 OpenIddict 包到支持 .NET 10 的版本,以确保认证和授权功能在升级后能够正常工作。OpenIddict 是我们项目中用于实现身份认证和授权的核心组件,升级过程中需要特别注意它与 ASP.NET Core 10 的兼容性,以及可能引入的破坏性变更。以下是检查列表:

  • OpenIddict 7.0.0 → 升级到最新版,确认 net10.0 TFM 支持

  • 涉及 4 个包,出现在 SP.Gateway 和 SP.IdentityService:

    包名 出现位置
    OpenIddict.AspNetCore IdentityService
    OpenIddict.EntityFrameworkCore IdentityService
    OpenIddict.Validation.AspNetCore Gateway、IdentityService
    OpenIddict.Validation.ServerIntegration Gateway
  • System.IdentityModel.Tokens.Jwt 8.12.1 → 升到最新版,确认与新版 OpenIddict 兼容(SP.Common)

  • Azure.Identity 1.11.4 → 升到最新版(SP.Gateway)

2.5 API 文档迁移 --- Swashbuckle → OpenAPI + Scalar

这一步的风险不大,但是工作量巨大。我们需要将所有微服务中使用的 Swashbuckle 包替换为 OpenAPI 和 Scalar 相关的包,以适应 .NET 10 的新特性和最佳实践。这个操作涉及到 API 文档生成和维护的核心部分,需要确保在替换过程中 API 文档能够正确生成,并且与现有的 API 定义保持一致。

1. 所有服务

这里是针对八个服务都需要升级的包,我们需要将以下 Swashbuckle 包替换为 OpenAPI 和 Scalar 相关的包,并且修改 Program.cs 中的 API 文档配置代码,以适应新的包和 .NET 10 的特性。以下是检查列表:

每个服务 .csproj

  • 移除 Swashbuckle.AspNetCore 6.6.2
  • 添加 Scalar.AspNetCore(NuGet 包)

每个服务 Program.cs

  • 移除 AddSwaggerGen(c => { ... }) 整个配置块(含 XML 注释、Bearer 安全配置)

  • 移除 app.UseSwagger()app.UseSwaggerUI()

  • 添加基于 .NET 10 OpenAPI 的新配置:

    csharp 复制代码
    // 注册 OpenAPI(含 JWT Bearer 安全方案)
    builder.Services.AddOpenApi(options =>
    {
        options.AddDocumentTransformer((document, context, ct) =>
        {
            document.Info = new() { Title = "服务名称 API", Version = "v1" };
            return Task.CompletedTask;
        });
        options.AddOperationTransformer((operation, context, ct) =>
        {
            // JWT Bearer 安全配置
            operation.Security = [new OpenApiSecurityRequirement
            {
                [new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    }
                }] = []
            }];
            return Task.CompletedTask;
        });
    });
    
    // 仅 Development/Local 环境暴露文档 UI
    if (app.Environment.IsDevelopment() || app.Environment.EnvironmentName == "Local")
    {
        app.MapOpenApi();
        app.MapScalarApiReference();  // 访问路径:/scalar/v1
    }

IdentityService 额外注意
SwaggerTokenRequestFilter 的逻辑需评估是否迁移为 IOpenApiOperationTransformer

2. SP.Gateway

网关服务中有些包需要单独的升级,并且 API 文档的聚合方案需要重新设计。由于我们之前使用 Swashbuckle 和 SwaggerForOcelot 来实现 API 文档的聚合展示,现在需要评估新的方案来替代它们,以适应 .NET 10 的新特性和最佳实践。以下是检查列表:

.csproj

  • 移除 Swashbuckle.AspNetCore 6.6.2MMLib.SwaggerForOcelot 8.3.2
  • 添加 Scalar.AspNetCore

Program.cs

  • 移除 AddSwaggerGen() + AddSwaggerForOcelot() 及其 UI 配置块
  • 移除 app.UseSwaggerForOcelotUI(...) 调用

Gateway 层文档聚合方案(二选一)

方案 说明
方案 A(推荐) 各下游服务通过 Ocelot 路由暴露自身 /openapi/v1.json,Gateway Scalar UI 配置多端点,分服务展示
方案 B 评估是否有支持 OpenAPI 的 SwaggerForOcelot 替代库
  • 同步清理 Nacos 中的 SwaggerConfig DataId 配置
2.6 API 网关 Ocelot 升级

这是一个高风险的步骤,我们需要将 Ocelot 包升级到支持 .NET 10 的版本,以确保 API 网关能够正常工作。Ocelot 是我们项目中用于实现 API 网关功能的核心组件,升级过程中需要特别注意它与 ASP.NET Core 10 的兼容性,以及可能引入的破坏性变更。以下是检查列表:

  • Ocelot 24.0.1 在 NuGet 确认支持 net10.0net9.0 的最新版本
  • 若最新版仅有 net9.0 TFM,.NET 10 可向下兼容引用,需验证功能正常
  • 升级后检查 ocelot.json 路由配置是否有破坏性变更
2.7 Baidu.AI OCR 替换 为 DeepSeek OCR 或其他 OCR 方案

进行这一步的目的是,由于Baidu.AI OCR SDK 目前不支持 .NET10,因此我们需要将其替换为 DeepSeek OCR ,以确保智能账单录入功能能够在升级后继续正常工作。

1. 移除 Baidu.AI

首先,我们要移除 Baidu.AI OCR SDK 相关的代码和配置,这包括:

  • .csproj 中移除 Baidu.AI 4.15.16
  • 删除或重命名 BaiduOCROptions.csDeepSeekOCROptions.cs
  • 移除 OCRConsumerService 中的 Ocr _clientBaidu.Aip.Ocr.Ocr)字段及初始化逻辑
  • 移除 Nacos/appsettings 中的 BaiduOCR 配置节
2. 新增 DeepSeek OCR 实现
  • 新建 DeepSeekOCROptions

    csharp 复制代码
    public class DeepSeekOCROptions
    {
        public string ApiKey { get; set; } = "";
        public string Endpoint { get; set; } = "https://api.deepseek.com";
        public string Model { get; set; } = "deepseek-chat";  // 需支持视觉的模型
    }
  • 修改 OCRServiceExtensions.cs

    csharp 复制代码
    public static IServiceCollection AddOCRService(
        this IServiceCollection services,
        IConfiguration configuration,
        string sectionName = "DeepSeekOCR")
    {
        services.Configure<DeepSeekOCROptions>(configuration.GetSection(sectionName));
        services.AddScoped<IOCRService, DeepSeekOCRServiceImpl>();  // 接口实现类无需改动
        return services;
    }

    IOCRService 接口和 BaiduOCRServiceImpl(仅负责发 RabbitMQ 消息)无需改动

  • 修改 OCRConsumerService.cs

    • 构造函数注入 IHttpClientFactory(替换 Ocr _client

    • 替换 Baidu API 调用代码块为 DeepSeek Vision API 调用:

      csharp 复制代码
      // 图片字节 → base64
      string base64Image = Convert.ToBase64String(image);
      string mimeType = "image/jpeg";  // 根据实际 ContentType 确定
      
      // 构造 DeepSeek Vision 请求
      var requestBody = new
      {
          model = _options.Model,
          messages = new[]
          {
              new
              {
                  role = "user",
                  content = new object[]
                  {
                      new { type = "image_url", image_url = new { url = $"data:{mimeType};base64,{base64Image}" } },
                      new { type = "text", text = "请识别图片中的所有文字,只输出文字内容,不要添加任何解释。" }
                  }
              }
          }
      };
      
      var response = await httpClient.PostAsJsonAsync("/chat/completions", requestBody, stoppingToken);
      response.EnsureSuccessStatusCode();
      
      var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: stoppingToken);
      string recognizedText = result
          .GetProperty("choices")[0]
          .GetProperty("message")
          .GetProperty("content")
          .GetString() ?? "";
    • 更新 appsettings 添加 DeepSeekOCR 配置节:

      json 复制代码
      "DeepSeekOCR": {
          "ApiKey": "",
          "Endpoint": "https://api.deepseek.com",
          "Model": "deepseek-chat"
      }
2.8 SP.MLService 服务中的 Microsoft.ML 升级到 .NET 10

这是一个高风险的步骤,我们需要将 SP.MLService 服务中使用的 Microsoft.ML 包升级到支持 .NET 10 的版本,以确保机器学习相关功能能够在升级后继续正常工作。Microsoft.ML 是我们项目中用于实现机器学习功能的核心组件,升级过程中需要特别注意它与 .NET 10 的兼容性,以及可能引入的破坏性变更。它被MLContextLightGbmRankingTrainer、Text Featurization Pipeline 使用,核心文件是CategoryMatcher.cs。以下是检查列表:

  • 确认 NuGet 上 Microsoft.MLMicrosoft.ML.LightGbm 是否有支持 net10.0net9.0 的版本
    • 若有 → 直接升级,在 Docker(Linux)和 Windows 两个平台测试原生库(LightGBM native binaries)加载
    • 若仅 net9.0 → 以兼容方式引用(.NET 10 向下兼容 net9 包)
  • 升级 Microsoft.MLMicrosoft.ML.LightGbm 到对应最新版
  • 升级 MongoDB.Driver 3.5.0 到最新版(FeedbackStorage 依赖)
  • 运行 CategoryMatcher 功能验证:训练 → 预测,确认排名结果正确
2.9 其余第三方包

最后,我们需要对项目中使用的其他第三方包进行升级,以确保它们与 .NET 10 兼容。这些包可能不如前面提到的核心包那样关键,但同样需要升级以避免潜在的兼容性问题,但是这一步属于低风险操作。以下是升级列表:

当前版本 风险 说明
Serilog 4.2.0 🟢 低 多 TFM,升最新版
Serilog.AspNetCore 8.0.1 🟢 低 升最新版
Serilog.Sinks.Grafana.Loki 8.3.0 🟢 低 升最新版
AutoMapper 14.0.0 🟢 低 多 TFM
Quartz 3.14.0 🟢 低 确认 net10 TFM
Quartz.AspNetCore 3.14.0 🟢 低 同上
RabbitMQ.Client 7.1.2 🟢 低 netstandard,兼容
StackExchange.Redis 2.7.33 🟢 低 netstandard,兼容
Refit 8.0.0 🟡 中 确认最新版 TFM
Refit.HttpClientFactory 8.0.0 🟡 中 同上
SixLabors.ImageSharp 3.1.11 🟢 低 多 TFM
SixLabors.Fonts 2.1.3 🟢 低 多 TFM
SixLabors.ImageSharp.Drawing 2.0.2 🟢 低 多 TFM
MongoDB.Driver 3.5.0 🟢 低 多 TFM
RestSharp 112.1.0 🟢 低 多 TFM
Minio 6.0.4 🟡 中 确认最新版 net10 支持
Twilio 7.13.0 🟢 低 多 TFM
Microsoft.Data.SqlClient 5.1.3 🟢 低 升最新版
2.10 破坏性变更代码审查

在完成上述升级步骤后,我们需要进行一次全面的代码审查,重点关注可能存在的破坏性变更。这包括但不限于以下几个方面:

  • EF Core 8 升级 10 Breaking Changes

    • 查阅官方文档
    • 重点关注:查询行为、Owned Entity、JSON 列映射变化
    • 逐一核对各服务 DbContext 和 LINQ 查询写法
  • ASP.NET Core Breaking Changes

  • OpenIddict 配置 API 变更

    • 对照新版 OpenIddict Changelog 检查 SP.IdentityService/Program.csSP.Gateway/Program.cs 中的 AddOpenIddict() 配置链
  • SwaggerTokenRequestFilter 迁移评估

    • 文件:SP.IdentityService/SwaggerTokenRequestFilter.cs
    • 评估其 Token 请求逻辑是否需要迁移为 IOpenApiOperationTransformer(.NET 10 OpenAPI 扩展点)
2.11 验证

升级完成后,我们需要进行全面的验证,确保项目在升级后能够正常运行,并且性能没有明显下降。这包括:

  • dotnet build 每个项目,确认零错误(顺序:SP.Common → 其余 8 个服务 → SP.Gateway
  • dotnet ef migrations list 验证各有迁移的服务历史状态完整
  • Docker Compose 启动,验证所有服务健康检查通过
  • 访问各服务 /scalar/v1,确认 Scalar UI 正常加载且 JWT Bearer 认证操作可用
  • 完整 AuthN 流程:Token 申请 → 刷新 → JwtBearer 验证
  • OCR 端对端测试:上传图片 → RabbitMQ 触发 → DeepSeek 识别 → DB 写入 → 查询识别结果
  • SP.MLService 分类预测:模型加载/训练 → 预测接口返回正确结果
  • 服务间 Refit HTTP 调用链联调测试
2.12 风险汇总

在这里,我们总结一下升级过程中可能遇到的风险点,在升级的过程中要格外注意:

风险等级 包 / 领域 说明
🔴 高(已决策) Swashbuckle + MMLib.SwaggerForOcelot 迁移到 OpenAPI + Scalar,需修改所有服务 Program.cs
🔴 高(已决策) Baidu.AI 替换为 DeepSeek Vision API,OCRConsumerService 需重写
🔴 高(随主线) Microsoft.ML / LightGbm 原生库 .NET 10 兼容性需验证,LightGBM native binaries 需测试
🟡 中 OpenIddict 版本升级后配置 API 可能有变化
🟡 中 Ocelot 需确认 net10 或 net9 版本可用
🟡 中 Pomelo EFCore MySQL EF Core 10 对应版本需确认 NuGet 可用
🟡 中 Refit 需确认最新版 TFM 支持
🟢 低 Microsoft.* 官方包 版本号随 .NET 升级,低风险
🟢 低 Serilog / AutoMapper / Quartz 等 多 TFM 库,向下兼容

三、总结

本篇文章我们详细介绍了将项目从 .NET 8 升级到 .NET 10 的准备工作和升级步骤。升级过程中,我们需要对项目的依赖关系进行全面梳理,制定详细的升级计划,并且按照步骤逐一完成基础框架升级、核心包升级、API 文档迁移、API 网关升级以及 OCR 方案替换等关键操作。在升级过程中,我们还需要特别注意可能存在的破坏性变更,并且在升级完成后进行全面的验证,确保项目能够正常运行并且性能没有明显下降。通过这次升级,我们不仅能够享受到 .NET 10 带来的性能优化和新特性,还能够为后续的 AI 智能化改造打下坚实的基础。

相关推荐
我是唐青枫11 小时前
C#.NET Span 深入解析:零拷贝内存切片与高性能实战
开发语言·c#·.net
qq_2320455717 小时前
精积微半导体面试(部分)
netty·策略模式·nio·内存抖动·threadlocal·bitmap·复用
light blue bird21 小时前
MES/ERP大数据报表条件索引查询组件
数据库·.net·winform·t-sql·大数据报表
唐青枫1 天前
C#.NET ReadOnlySequence 深入解析:多段内存遍历与零拷贝协议解析
c#·.net
我是唐青枫2 天前
C#.NET Memory 深入解析:跨异步边界的内存视图与高性能实战
开发语言·c#·.net
light blue bird2 天前
MES/ERP报表大致化元素组排类查询
jvm·数据库·.net·ai大数据
badhope2 天前
OpenClaw卸载命令全解析
java·linux·人工智能·python·sql·数据挖掘·策略模式
喵叔哟2 天前
8. 【Blazor全栈开发实战指南】--路由与导航
数据库·微服务·.net