mcpField
D
dotnet-modernize

dotnet-modernize

github.com/wshaddix开发8679 次安装35 周前更新
代码仓库

关于 dotnet-modernize

用于检查现有 .NET 代码现代化机会的技能,可识别过时框架、包、API 模式及缺失的实践。它提供可执行建议,但不负责实施升级。

主要功能

  1. 01检查目标框架
  2. 02标记已弃用的包
  3. 03识别被取代的 API 模式
  4. 04检查构建配置缺项
  5. 05指出安全与合规问题

适用场景

  1. 01查找已停止支持的目标框架
  2. 02规划包替换工作
  3. 03定位较旧的代码模式
  4. 04确定安全与维护问题的优先级

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-modernize

安装后在 Claude Code 中输入/dotnet-modernize确认已加载。

详细介绍

dotnet-modernize

分析现有 .NET 代码,寻找现代化机会。识别过时的目标框架、已弃用的包、已被取代的 API 模式,以及缺失的现代最佳实践。针对每项发现提供可执行的建议。

范围边界:此技能仅标记机会。如需了解实际迁移路径、polyfill 策略、多目标框架指导和逐步版本升级流程,请参阅 [skill:dotnet-version-upgrade] 和 [skill:dotnet-multi-targeting]。

**前置条件:**先运行 [skill:dotnet-version-detection],以确定当前 SDK、TFM 和语言版本。运行 [skill:dotnet-project-analysis],了解解决方案结构和依赖项。

交叉引用:[skill:dotnet-project-structure] 介绍现代布局约定,[skill:dotnet-add-analyzers] 介绍基于分析器检测已弃用模式,[skill:dotnet-scaffold-project] 介绍完全现代化项目的目标状态。


现代化检查清单

根据此清单检查现有代码库。每个部分都会说明要查找的内容以及现代替代方案。

1. 目标框架

检查 .csproj 文件(或 Directory.Build.props)中的 <TargetFramework>:

当前 TFM状态建议
net8.0LTS——支持至 2026 年 11 月计划升级到 net10.0(LTS)
net9.0STS——支持于 2026 年 5 月结束尽快升级到 net10.0
net7.0已终止支持立即升级
net6.0已终止支持立即升级
net5.0 或更低版本已终止支持立即升级
netstandard2.0/2.1受支持(库兼容性)如果采用多目标框架以扩大覆盖范围,则保留
netcoreapp3.1已终止支持立即升级
.NET Framework 4.x旧版评估迁移可行性

扫描所有项目:

# Find all TFMs in the solution
find . -name "*.csproj" -exec grep -h "TargetFramework" {} \; | sort -u

# Check Directory.Build.props
grep "TargetFramework" Directory.Build.props 2>/dev/null

2. 已弃用和已被取代的包

扫描 Directory.Packages.props(或各个 .csproj 文件),查找已被取代的包:

已弃用的包替代方案起始版本
Microsoft.Extensions.Http.PollyMicrosoft.Extensions.Http.Resilience.NET 8
Newtonsoft.Json(新项目)System.Text.Json.NET Core 3.0+
Microsoft.AspNetCore.Mvc.NewtonsoftJson内置 STJ.NET Core 3.0+
Swashbuckle.AspNetCore用于生成文档的内置 OpenAPI(Microsoft.AspNetCore.OpenApi);若使用 Swagger UI、筛选器或代码生成,则保留 Swashbuckle.NET 9
NSwag.AspNetCore用于生成文档的内置 OpenAPI;若使用客户端生成或 Swagger UI 功能,则保留 NSwag.NET 9
Microsoft.Extensions.Logging.Log4Net.AspNetCore内置日志记录 + Serilog 或 OpenTelemetry.NET Core 2.0+
Microsoft.AspNetCore.Authentication.JwtBearer(显式 NuGet 包)移除显式 PackageReference——已包含在 Microsoft.AspNetCore.App 共享框架中.NET Core 3.0+
System.Data.SqlClientMicrosoft.Data.SqlClient.NET Core 3.0+
Microsoft.Azure.Storage.*Azure.Storage.*2020+
WindowsAzure.StorageAzure.Storage.Blobs / Azure.Storage.Queues2020+
Microsoft.Azure.ServiceBusAzure.Messaging.ServiceBus2020+
Microsoft.Azure.EventHubsAzure.Messaging.EventHubs2020+
EntityFramework(EF6)Microsoft.EntityFrameworkCore.NET Core 1.0+
RestSharp(旧版本)HttpClient + System.Text.Json.NET Core+
AutoMapper手动映射或源生成映射器偏好

扫描已弃用的包:

# List all package references
grep -rh "PackageVersion\|PackageReference" \
  Directory.Packages.props $(find . -name "*.csproj") 2>/dev/null | \
  grep -i "Include=" | sort -u

**关于 Newtonsoft.Json 的说明:**大量使用 Newtonsoft.Json 的现有项目(自定义转换器、JObject 操作)可能无法从立即迁移中获益。请标记此项,但评估迁移成本。


3. 已被取代的 API 模式

查找已有现代替代方案的代码模式:

Startup.cs / Program.cs 模式

旧版(.NET 6 之前):

public class Startup
{
    public void ConfigureServices(IServiceCollection services) { }
    public void Configure(IApplicationBuilder app) { }
}

现代版(最简托管):

var builder = WebApplication.CreateBuilder(args);
// ConfigureServices equivalent
var app = builder.Build();
// Configure equivalent
app.Run();
HttpClient 注册

旧版:

services.AddHttpClient<MyService>(client =>
{
    client.BaseAddress = new Uri("https://api.example.com");
})
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(300)));

现代版(使用 Microsoft.Extensions.Resilience):

services.AddHttpClient<MyService>(client =>
{
    client.BaseAddress = new Uri("https://api.example.com");
})
.AddStandardResilienceHandler();
同步 I/O

标记: File.ReadAllText、Stream.Read、不带 Async 后缀的 HttpClient。

现代做法: 使用 async 变体——File.ReadAllTextAsync、Stream.ReadAsync、await httpClient.GetAsync()。

热路径中的字符串拼接

标记: 日志记录、循环中使用字符串拼接(+)或 String.Format。

现代做法: 使用字符串插值配合 LoggerMessage 源生成器,或使用 StringBuilder。

旧式集合模式

标记: Hashtable、ArrayList、非泛型集合。

现代做法: 使用 Dictionary<TKey, TValue>、List<T>、泛型集合。

ILogger 模式

旧版:

_logger.LogInformation("Processing order {OrderId}", orderId);

现代版(高性能):

[LoggerMessage(Level = LogLevel.Information, Message = "Processing order {OrderId}")]
static partial void LogProcessingOrder(ILogger logger, string orderId);

4. 缺少现代构建配置

检查是否缺少推荐的构建基础设施:

缺少项检查方式建议
集中式包管理没有 Directory.Packages.props参见 [skill:dotnet-project-structure]
Directory.Build.props属性分散在多个 .csproj 文件中集中共享属性
.editorconfig仓库根目录没有 .editorconfig参见 [skill:dotnet-project-structure]
global.json没有固定 SDK 版本添加以确保可重复构建
NuGet 审计没有 NuGetAudit 属性在 Directory.Build.props 中启用
锁定文件没有 RestorePackagesWithLockFile启用以确保还原结果确定
包源映射nuget.config 中没有 packageSourceMapping添加以保障供应链安全
分析器没有 AnalysisLevel 或 EnforceCodeStyleInBuild参见 [skill:dotnet-add-analyzers]
SourceLink没有 SourceLink 包引用添加以支持调试器源代码导航
可空引用类型未启用 <Nullable>全局启用
.slnx在 .NET 9+ SDK 中仍使用 .sln使用 dotnet sln migrate 迁移

5. 已弃用的 C# 语言模式
旧模式现代替代方式语言版本
带 case 的 switch 语句switch 表达式C# 8
null != x / x != null 检查x is not nullC# 9
类型明显时使用 new ClassName()目标类型推断的 new()C# 9
块范围命名空间文件范围命名空间C# 10
显式构造函数的 record class使用位置参数的 recordC# 10
手动拼接多行字符串原始字符串字面量("""...""")C# 11
对 INumber<T> 显式分派接口泛型数学接口C# 11
手动检查 [Flags] 枚举改进的枚举模式匹配C# 11+
没有自然类型的 Lambda自然函数类型C# 10+
手动包装 ValueTask使用 ConfigureAwait 模式的 Task/ValueTaskC# 所有版本
手动编写主构造函数类在 class/struct 上使用主构造函数C# 12
多个 if/else if 类型检查对类型使用带列表模式的 switchC# 11+
params T[]params ReadOnlySpan<T>、params 集合C# 13
使用 object 的锁System.Threading.LockC# 13

6. 安全与合规
问题检测方式修复方法
已知漏洞dotnet list package --vulnerable更新受影响的包
已弃用的包dotnet list package --deprecated替换为后续版本
过时的包dotnet list package --outdated评估更新
缺少 HTTPS 重定向没有 app.UseHttpsRedirection()添加到管道中
缺少 HSTS没有 app.UseHsts()在生产环境中添加
硬编码密钥appsettings.json 中包含连接字符串使用 User Secrets 或 Key Vault
# Run all NuGet audits
dotnet list package --vulnerable --include-transitive
dotnet list package --deprecated
dotnet list package --outdated

运行现代化扫描

将这些检查组合起来,进行系统化扫描:

# 1. Check TFMs
echo "=== Target Frameworks ==="
find . -name "*.csproj" -exec grep -Hl "TargetFramework" {} \; | while read f; do
  echo "$f: $(grep -o '<TargetFramework[s]*>[^<]*' "$f" | head -1)"
done

# 2. Check for deprecated packages
echo "=== Package Audit ==="
dotnet list package --deprecated 2>/dev/null
dotnet list package --vulnerable --include-transitive 2>/dev/null

# 3. Check build infrastructure
echo "=== Build Infrastructure ==="
test -f Directory.Build.props && echo "OK: Directory.Build.props" || echo "MISSING: Directory.Build.props"
test -f Directory.Packages.props && echo "OK: Directory.Packages.props (CPM)" || echo "MISSING: Directory.Packages.props"
test -f .editorconfig && echo "OK: .editorconfig" || echo "MISSING: .editorconfig"
test -f global.json && echo "OK: global.json" || echo "MISSING: global.json"
test -f nuget.config && echo "OK: nuget.config" || echo "MISSING: nuget.config"

# 4. Check for old patterns in code
echo "=== Code Patterns ==="
grep -rl "class Startup" --include="*.cs" . 2>/dev/null && echo "FOUND: Legacy Startup.cs pattern"
grep -rl "Microsoft.Extensions.Http.Polly" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: Deprecated Polly package"
grep -rl "Swashbuckle" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: Swashbuckle (consider built-in OpenAPI for .NET 9+)"
grep -rl "System.Data.SqlClient" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: System.Data.SqlClient (use Microsoft.Data.SqlClient)"

确定现代化改造的优先级

并非所有现代化改造都同样紧迫。请按影响确定优先级:

  1. 安全性 -- 存在漏洞的包、已结束生命周期的 TFM(不再提供安全补丁)
  2. 可维护性 -- 已弃用且上游不再维护的包
  3. 性能 -- 对性能有显著影响的模式(同步调用异步、热路径中使用旧版集合)
  4. 开发者体验 -- 构建基础设施(CPM、分析器、editorconfig)可改善日常工作流
  5. 代码风格 -- 语言模式更新的优先级最低,但随着时间推移可以降低认知负担

接下来

此技能会标记现代化改造机会。如需执行升级:

  • TFM 版本升级和迁移路径 -- [技能:dotnet-version-upgrade]
  • 多目标策略 -- [技能:dotnet-multi-targeting]
  • 用于跨版本支持的 Polyfill 包 -- [技能:dotnet-multi-targeting]
  • 补充缺失的构建基础设施 -- [技能:dotnet-project-structure]、[技能:dotnet-scaffold-project]
  • 配置分析器 -- [技能:dotnet-add-analyzers]
  • 添加 CI/CD -- [技能:dotnet-add-ci]

参考资料

评论

支持 Markdown