dotnet tool install -g upgrade-assistant && upgrade-assistant upgrade <project.csproj> (legacy, deprecated but functional).System.Drawing.Common throws PlatformNotSupportedException on Linux/macOS in .NET 6+. Use SkiaSharp or ImageSharp for cross-platform. [src1]| .NET Framework Pattern | .NET 10 Equivalent | Notes |
|---|---|---|
System.Web.HttpContext | Microsoft.AspNetCore.Http.HttpContext | Completely different API -- use System.Web adapters for incremental migration [src5] |
Web.config (XML) | appsettings.json + Options pattern | Use IOptions<T> / IConfiguration for strongly-typed settings [src6] |
Global.asax / Application_Start | Program.cs / WebApplication.CreateBuilder() | Minimal hosting model in .NET 6+; Startup.cs optional [src3] |
HTTP Modules (IHttpModule) | Middleware (IMiddleware / convention) | Register in app.UseMiddleware<T>(); order matters [src6] |
HTTP Handlers (IHttpHandler) | Middleware or MapGet/MapPost endpoints | Use minimal APIs or controller endpoints [src6] |
packages.config | PackageReference in .csproj | Migrate via VS right-click > "Migrate packages.config to PackageReference" [src1] |
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> | <TargetFramework>net10.0</TargetFramework> | SDK-style project format required [src1] |
| WCF (server-side) | gRPC, CoreWCF 2.x, or REST API | CoreWCF 2.x supports .NET 8/10; gRPC recommended for new services [src7] |
| Entity Framework 6 | Entity Framework Core 10 | Different API surface; migrations not directly compatible [src2] |
System.Web.Mvc.Controller | Microsoft.AspNetCore.Mvc.Controller | Namespace swap; action filters and model binding differ [src3] |
FormsAuthentication | ASP.NET Core Identity / Cookie Auth | Use AddAuthentication().AddCookie(); passkey auth in .NET 10 [src3, src8] |
System.Drawing (GDI+) | SkiaSharp or ImageSharp | System.Drawing.Common is Windows-only in .NET 6+ [src1] |
AppDomain.CreateDomain() | Separate process or AssemblyLoadContext | AppDomains not supported; use containers for isolation [src1] |
.NET Remoting | gRPC, REST, System.IO.Pipes, or StreamJsonRpc | Remoting calls throw PlatformNotSupportedException [src1] |
BundleConfig.cs (bundling) | Webpack, Vite, or dotnet bundle | Built-in bundling removed; use standard frontend tooling [src3] |
BinaryFormatter | System.Text.Json or MessagePack | BinaryFormatter fully removed in .NET 10 [src9] |
START
|-- Is the app ASP.NET Web Forms?
| |-- YES -> No direct port path. Rewrite in Blazor Server/WASM or Razor Pages [src1]
| +-- NO v
|-- Is the app a class library or console app?
| |-- YES -> Convert to SDK-style project, retarget to net10.0, fix API incompatibilities [src1]
| +-- NO v
|-- Is the app ASP.NET MVC / Web API?
| |-- YES -> Is it a large production app (>50K LOC)?
| | |-- YES -> Use incremental migration (YARP proxy + Strangler Fig) [src5]
| | +-- NO -> Use GitHub Copilot app modernization or legacy Upgrade Assistant [src4]
| +-- NO v
|-- Is it WinForms or WPF?
| |-- YES -> Convert to SDK-style project, retarget to net10.0-windows [src1]
| +-- NO v
|-- Does it use WCF server-side?
| |-- YES -> Port to CoreWCF 2.x (API-compatible) or rewrite as gRPC/REST [src7]
| +-- NO v
+-- DEFAULT -> Analyze with GitHub Copilot app modernization or legacy Upgrade Assistant [src4]
Run the GitHub Copilot app modernization agent (VS 2026) or the legacy .NET Upgrade Assistant analysis to identify incompatible APIs, unsupported technologies, and third-party library gaps. [src1, src4]
# Option A: Legacy CLI (deprecated but functional)
dotnet tool install -g upgrade-assistant
upgrade-assistant analyze <MySolution.sln>
# Option B: In Visual Studio 2026, open Copilot Chat and type:
# "Analyze this solution for migration from .NET Framework to .NET 10"
Verify: Review the generated report. Note any APIs flagged as unsupported.
Ensure your project targets .NET Framework 4.7.2 or later. This maximizes API overlap with .NET Standard 2.0. [src1]
<!-- Update TargetFrameworkVersion -->
<PropertyGroup>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
</PropertyGroup>
Verify: msbuild /t:Restore && msbuild completes with no errors. Run full test suite.
Migrate from legacy .csproj format to SDK-style. Required for targeting modern .NET. [src1]
# Use try-convert tool
dotnet tool install -g try-convert
try-convert --project <MyProject.csproj>
Verify: dotnet build succeeds. NuGet packages use PackageReference.
Convert from packages.config to PackageReference format. [src1]
<!-- In .csproj: replace packages.config with -->
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
Verify: dotnet restore succeeds. Delete the old packages.config.
Change target framework to net10.0. Fix compilation errors from missing APIs. [src1, src8]
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
# Add Windows Compatibility Pack for missing APIs
dotnet add package Microsoft.Windows.Compatibility
Verify: dotnet build succeeds. Run tests. Fix any PlatformNotSupportedException.
For ASP.NET MVC/WebAPI, replace System.Web with ASP.NET Core equivalents. For large apps, use incremental YARP proxy approach. [src3, src5]
// BEFORE: using System.Web.Mvc;
// public class HomeController : Controller { public ActionResult Index() ... }
// AFTER: using Microsoft.AspNetCore.Mvc;
// public class HomeController : Controller { public IActionResult Index() ... }
Verify: Routes return the same responses. Compare HTTP status codes and response bodies.
Migrate WCF, Entity Framework 6, and other unsupported libraries to modern equivalents. [src1, src7]
// WCF -> gRPC (or CoreWCF for direct port)
// EF6 DbContext -> EF Core 10 DbContext with OnConfiguring
Verify: All database queries return correct results. Run integration tests.
// Input: An ASP.NET Framework HTTP module (IHttpModule) for request logging
// Output: Equivalent ASP.NET Core middleware with DI support
// BEFORE: ASP.NET Framework HTTP Module
// public class RequestLoggingModule : IHttpModule
// {
// public void Init(HttpApplication application)
// {
// application.BeginRequest += (s, e) => {
// var context = ((HttpApplication)s).Context;
// Debug.WriteLine($"Request: {context.Request.Url}");
// };
// }
// public void Dispose() { }
// }
// AFTER: ASP.NET Core Middleware
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(RequestDelegate next,
ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
_logger.LogInformation("Request: {Method} {Path}",
context.Request.Method, context.Request.Path);
await _next(context);
_logger.LogInformation("Response: {StatusCode}",
context.Response.StatusCode);
}
}
// Registration in Program.cs:
// app.UseMiddleware<RequestLoggingMiddleware>();
// Input: XML Web.config AppSettings + ConfigurationManager usage
// Output: JSON appsettings.json + IOptions<T> injection
// BEFORE: Web.config
// <appSettings>
// <add key="SmtpHost" value="smtp.example.com" />
// <add key="SmtpPort" value="587" />
// </appSettings>
// Usage: ConfigurationManager.AppSettings["SmtpHost"]
// AFTER: appsettings.json
// { "EmailSettings": { "SmtpHost": "smtp.example.com", "SmtpPort": 587 } }
public class EmailSettings
{
public string SmtpHost { get; set; } = "";
public int SmtpPort { get; set; } = 587;
public int MaxRetries { get; set; } = 3;
}
// Registration: builder.Services.Configure<EmailSettings>(
// builder.Configuration.GetSection("EmailSettings"));
public class EmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> options)
{
_settings = options.Value;
}
public void Send(string to, string subject, string body)
{
using var client = new SmtpClient(_settings.SmtpHost, _settings.SmtpPort);
// send logic with _settings.MaxRetries retry attempts
}
}
// Input: ASP.NET Framework Global.asax with Application_Start
// Output: ASP.NET Core Program.cs with equivalent startup and middleware
// BEFORE: Global.asax.cs
// public class MvcApplication : HttpApplication {
// protected void Application_Start() {
// AreaRegistration.RegisterAllAreas();
// FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// RouteConfig.RegisterRoutes(RouteTable.Routes);
// }
// }
// AFTER: Program.cs (.NET 10)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
builder.Services.AddLogging();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
// BAD -- ConfigurationManager does not work with appsettings.json
using System.Configuration;
var host = ConfigurationManager.AppSettings["SmtpHost"]; // Returns null
// GOOD -- Built-in configuration reads appsettings.json
public class EmailService
{
public EmailService(IConfiguration config)
{
var host = config["EmailSettings:SmtpHost"];
}
}
// BAD -- System.Web does not exist in .NET Core
using System.Web;
public string GetClientIp(HttpContext context)
{
return context.Request.UserHostAddress;
}
// GOOD -- ASP.NET Core HttpContext
using Microsoft.AspNetCore.Http;
public string GetClientIp(HttpContext context)
{
return context.Connection.RemoteIpAddress?.ToString() ?? "unknown";
}
<!-- BAD -- Old-format project files have hundreds of lines -->
<Project ToolsVersion="15.0" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\..." />
<!-- 200+ lines -->
</Project>
<!-- GOOD -- SDK-style: clean, minimal -->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
</ItemGroup>
</Project>
// BAD -- Rewriting everything at once stalls feature development
// "Freeze features and rewrite the entire 200K LOC app in .NET 10"
// Result: 6+ months delay, regressions, team burnout
// GOOD -- Strangler Fig: migrate one route at a time
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
// Proxy unmigrated routes to legacy .NET Framework app
// BAD -- BinaryFormatter fully removed in .NET 10 (disabled .NET 8, removed .NET 9+)
var formatter = new BinaryFormatter();
formatter.Serialize(stream, myObject); // Compile error in .NET 10
// GOOD -- System.Text.Json is the default serializer
using System.Text.Json;
var json = JsonSerializer.Serialize(myObject);
var obj = JsonSerializer.Deserialize<MyType>(json);
<!-- BAD -- .NET 8 LTS support ends November 2026 -->
<TargetFramework>net8.0</TargetFramework>
<!-- GOOD -- .NET 10 LTS supported until November 2028 -->
<TargetFramework>net10.0</TargetFramework>
AssemblyLoadContext instead of AppDomains. [src1]Microsoft.Windows.Compatibility, or find alternative packages. [src1]dotnet ef dbcontext scaffold. [src2]PlatformNotSupportedException on Linux/macOS. Fix: Use SkiaSharp or ImageSharp for cross-platform image processing. [src1]System.Text.Json, MessagePack, or Protocol Buffers. Audit all [Serializable] attributes. [src2, src9]Program.cs using builder.Services.AddScoped<T>(). [src3]false in .NET Core (was true in .NET Framework). Fix: Explicitly set UseShellExecute = true if your code relies on shell execution. [src2]PackageReference entries with dotnet restore and cross-check on nuget.org. [src4]# Check installed .NET SDKs and runtimes
dotnet --list-sdks
dotnet --list-runtimes
# Analyze a project for migration issues (legacy CLI, deprecated)
dotnet tool install -g upgrade-assistant
upgrade-assistant analyze <MySolution.sln>
# Check API compatibility against .NET 10
dotnet tool install -g apicompat
apicompat -a <MyAssembly.dll> -f net10.0
# List NuGet packages and check for updates
dotnet list package --outdated
dotnet list package --vulnerable
# Convert old project format to SDK-style
dotnet tool install -g try-convert
try-convert --project <MyProject.csproj>
# Scaffold EF Core context from existing database
dotnet ef dbcontext scaffold "Server=.;Database=MyDb;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Models
# Verify target framework and SDK version
dotnet --info
| Version | Status | Release | Key Migration Notes |
|---|---|---|---|
| .NET 10 | LTS (Current) | Nov 2025 | Recommended target. LTS until Nov 2028. C# 14, AI integration, NativeAOT, post-quantum crypto, passkey auth. |
| .NET 9 | EOL (May 2026) | Nov 2024 | STS -- 18 months. AOT improvements. Migrate to .NET 10 before May 2026. |
| .NET 8 | LTS (EOL Nov 2026) | Nov 2023 | LTS until Nov 2026. Blazor SSR, Native AOT for ASP.NET Core. Plan upgrade to .NET 10. |
| .NET 7 | EOL (May 2024) | Nov 2022 | Skip -- go directly to .NET 10. |
| .NET 6 | EOL (Nov 2024) | Nov 2021 | Minimal hosting introduced. Was LTS. |
| .NET 5 | EOL (May 2022) | Nov 2020 | First unified .NET brand. Skip. |
| .NET Core 3.1 | EOL (Dec 2022) | Dec 2019 | Last "Core" version. WinForms/WPF added. |
| .NET Framework 4.8.1 | Maintained | Aug 2022 | Last .NET Framework release. Security patches only. |
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Starting any new .NET project | App exclusively uses Web Forms with no rewrite budget | Stay on .NET Framework 4.8 |
| App needs cross-platform (Linux containers) | Small internal tool working fine on .NET Framework | Maintain as-is until EOL pressure |
| Performance is critical (Kestrel is faster than IIS+System.Web) | Heavy COM+ / EnterpriseServices dependency | Stay on .NET Framework or refactor first |
| Team wants modern C# features (records, primary constructors) | Massive WCF server with hundreds of contracts | Port to CoreWCF first |
| Hosting costs matter (Linux is cheaper) | All third-party deps target only .NET Framework | Wait for package updates |
| Need Native AOT or container deployment | Project in maintenance mode, no active development | Leave on .NET Framework |
| Need AI integration (Microsoft.Extensions.AI, MCP support) | Migration budget exhausted and .NET Framework still patched | Defer migration |
Microsoft.Windows.Compatibility NuGet package provides many .NET Framework APIs on .NET Core, but some are Windows-only stubs that throw PlatformNotSupportedException on Linux/macOS. [src1]<TargetFrameworks>net472;net10.0</TargetFrameworks>) doubles build and test time but enables gradual migration. [src7]