dotnet-modernize

Analyzing .NET code for modernization. Outdated TFMs, deprecated packages, superseded patterns.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "dotnet-modernize" with this command: npx skills add wshaddix/dotnet-skills/wshaddix-dotnet-skills-dotnet-modernize

dotnet-modernize

Analyze existing .NET code for modernization opportunities. Identifies outdated target frameworks, deprecated packages, superseded API patterns, and missing modern best practices. Provides actionable recommendations for each finding.

Scope boundary: This skill flags opportunities only. For actual migration paths, polyfill strategies, multi-targeting guidance, and step-by-step version upgrade procedures, see [skill:dotnet-version-upgrade] and [skill:dotnet-multi-targeting].

Prerequisites: Run [skill:dotnet-version-detection] first to determine the current SDK, TFM, and language version. Run [skill:dotnet-project-analysis] to understand solution structure and dependencies.

Cross-references: [skill:dotnet-project-structure] for modern layout conventions, [skill:dotnet-add-analyzers] for analyzer-based detection of deprecated patterns, [skill:dotnet-scaffold-project] for the target state of a fully modernized project.


Modernization Checklist

Run through this checklist against the existing codebase. Each section identifies what to look for and what the modern replacement is.

1. Target Framework

Check <TargetFramework> in .csproj files (or Directory.Build.props):

Current TFMStatusRecommendation
net8.0LTS -- supported until Nov 2026Plan upgrade to net10.0 (LTS)
net9.0STS -- support ends May 2026Upgrade to net10.0 promptly
net7.0End of lifeUpgrade immediately
net6.0End of lifeUpgrade immediately
net5.0 or lowerEnd of lifeUpgrade immediately
netstandard2.0/2.1Supported (library compat)Keep if multi-targeting for broad reach
netcoreapp3.1End of lifeUpgrade immediately
.NET Framework 4.xLegacyEvaluate migration feasibility

To scan all projects:

# 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. Deprecated and Superseded Packages

Scan Directory.Packages.props (or individual .csproj files) for packages that have been superseded:

Deprecated PackageReplacementSince
Microsoft.Extensions.Http.PollyMicrosoft.Extensions.Http.Resilience.NET 8
Newtonsoft.Json (new projects)System.Text.Json.NET Core 3.0+
Microsoft.AspNetCore.Mvc.NewtonsoftJsonBuilt-in STJ.NET Core 3.0+
Swashbuckle.AspNetCoreBuilt-in OpenAPI (Microsoft.AspNetCore.OpenApi) for document generation; keep Swashbuckle if using Swagger UI, filters, or codegen.NET 9
NSwag.AspNetCoreBuilt-in OpenAPI for document generation; keep NSwag if using client generation or Swagger UI features.NET 9
Microsoft.Extensions.Logging.Log4Net.AspNetCoreBuilt-in logging + Serilog or OpenTelemetry.NET Core 2.0+
Microsoft.AspNetCore.Authentication.JwtBearer (explicit NuGet package)Remove explicit PackageReference — included in Microsoft.AspNetCore.App shared framework.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 (older versions)HttpClient + System.Text.Json.NET Core+
AutoMapperManual mapping or source-generated mappersPreference

To scan for deprecated packages:

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

Note on Newtonsoft.Json: Existing projects with deep Newtonsoft.Json usage (custom converters, JObject manipulation) may not benefit from immediate migration. Flag it but assess the migration cost.


3. Superseded API Patterns

Look for code patterns that have modern replacements:

Startup.cs / Program.cs Pattern

Old (pre-.NET 6):

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

Modern (minimal hosting):

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

HttpClient Registration

Old:

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

Modern (with Microsoft.Extensions.Resilience):

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

Synchronous I/O

Flag: File.ReadAllText, Stream.Read, HttpClient without Async suffix.

Modern: Use async variants -- File.ReadAllTextAsync, Stream.ReadAsync, await httpClient.GetAsync().

String Concatenation in Hot Paths

Flag: String concatenation (+) or String.Format in logging, loops.

Modern: Use string interpolation with LoggerMessage source generators, or StringBuilder.

Legacy Collection Patterns

Flag: Hashtable, ArrayList, non-generic collections.

Modern: Dictionary<TKey, TValue>, List<T>, generic collections.

ILogger Pattern

Old:

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

Modern (high-performance):

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

4. Missing Modern Build Configuration

Check for the absence of recommended build infrastructure:

MissingCheckRecommendation
Central Package ManagementNo Directory.Packages.propsSee [skill:dotnet-project-structure]
Directory.Build.propsProperties scattered across .csproj filesCentralize shared properties
.editorconfigNo .editorconfig at repo rootSee [skill:dotnet-project-structure]
global.jsonNo SDK pinningAdd for reproducible builds
NuGet auditNo NuGetAudit propertyEnable in Directory.Build.props
Lock filesNo RestorePackagesWithLockFileEnable for deterministic restores
Package source mappingNo packageSourceMapping in nuget.configAdd for supply-chain security
AnalyzersNo AnalysisLevel or EnforceCodeStyleInBuildSee [skill:dotnet-add-analyzers]
SourceLinkNo SourceLink package referenceAdd for debugger source navigation
Nullable reference types<Nullable> not enabledEnable globally
.slnxStill using .sln with .NET 9+ SDKMigrate with dotnet sln migrate

5. Deprecated C# Language Patterns

Old PatternModern ReplacementLanguage Version
switch statement with caseswitch expressionC# 8
null != x / x != null checksx is not nullC# 9
new ClassName() with obvious typeTarget-typed new()C# 9
Block-scoped namespacesFile-scoped namespacesC# 10
record class explicit constructorrecord with positional parametersC# 10
Manual string concatenation for multi-lineRaw string literals ("""...""")C# 11
Explicit interface dispatch for INumber<T>Generic math interfacesC# 11
[Flags] enum manual checksImproved enum pattern matchingC# 11+
Lambda without natural typeNatural function typesC# 10+
ValueTask manual wrappingTask/ValueTask with ConfigureAwait patternsC# all
Primary constructor classes (manual)Primary constructors on class/structC# 12
Multiple if/else if type checksswitch on type with list patternsC# 11+
params T[]params ReadOnlySpan<T>, params collectionsC# 13
Lock with objectSystem.Threading.LockC# 13

6. Security and Compliance

IssueDetectionFix
Known vulnerabilitiesdotnet list package --vulnerableUpdate affected packages
Deprecated packagesdotnet list package --deprecatedReplace with successors
Outdated packagesdotnet list package --outdatedEvaluate updates
Missing HTTPS redirectionNo app.UseHttpsRedirection()Add to pipeline
Missing HSTSNo app.UseHsts()Add for production
Hardcoded secretsConnection strings in appsettings.jsonUse User Secrets or Key Vault
# Run all NuGet audits
dotnet list package --vulnerable --include-transitive
dotnet list package --deprecated
dotnet list package --outdated

Running a Modernization Scan

Combine the checks into a systematic scan:

# 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)"

Prioritizing Modernization

Not all modernization is equally urgent. Prioritize by impact:

  1. Security -- vulnerable packages, end-of-life TFMs (no security patches)
  2. Supportability -- deprecated packages with no upstream maintenance
  3. Performance -- patterns with significant perf impact (sync-over-async, legacy collections in hot paths)
  4. Developer experience -- build infrastructure (CPM, analyzers, editorconfig) improves daily workflow
  5. Code style -- language pattern updates are lowest priority but reduce cognitive load over time

What's Next

This skill flags modernization opportunities. For executing upgrades:

  • TFM version upgrades and migration paths -- [skill:dotnet-version-upgrade]
  • Multi-targeting strategies -- [skill:dotnet-multi-targeting]
  • Polyfill packages for cross-version support -- [skill:dotnet-multi-targeting]
  • Adding missing build infrastructure -- [skill:dotnet-project-structure], [skill:dotnet-scaffold-project]
  • Configuring analyzers -- [skill:dotnet-add-analyzers]
  • Adding CI/CD -- [skill:dotnet-add-ci]

References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

dotnet-csharp-code-smells

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

dotnet-cli-distribution

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

dotnet-http-client

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

dotnet-maui-development

No summary provided by upstream source.

Repository SourceNeeds Review