Your company still runs .NET Framework 4.x. The codebase is ten years old, maybe older. Everyone agrees it should move to .NET 8 or 9. Nobody wants to be the one to start.

I get it. Framework migrations are tedious, risky, and boring in all the worst ways. You’re not building anything new — you’re rewriting what already works, hoping you don’t break it in the process.

But I’ve been using Claude Code to help with these migrations, and it turns a soul-crushing project into something manageable. Here’s how.


Step 1: Assessment — know what you’re dealing with

Before you change a single line, you need to understand what you have. Ask Claude Code to analyze your solution:

“Scan this solution. List all projects, their target frameworks, NuGet packages, and any Framework-specific APIs like System.Web, WCF, or COM interop.”

Claude Code will go through your .csproj files, packages.config files, and source code. It builds a dependency map you’d normally spend days creating in a spreadsheet.

The output tells you which projects are straightforward (class libraries with no Framework dependencies) and which ones will hurt (ASP.NET WebForms, WCF services, anything touching System.Web).

This step alone saves you a week of manual inventory work.


Step 2: Plan the migration path

Big bang or incremental? It depends on your solution structure, and Claude Code can help you decide.

Ask it: “Given these dependencies between projects, what’s the migration order? Which projects can I migrate independently?”

Claude Code maps the dependency graph and suggests a bottom-up approach: start with shared libraries that have no Framework-specific dependencies, then work your way up to the web and service projects.

For most real-world solutions, incremental is the right answer. You migrate one project at a time, keep the solution building, and ship along the way. Big bang only works if your solution is small or you enjoy three-month feature freezes.


Step 3: Convert to SDK-style project files

This is where Claude Code really shines. Old-style .csproj files are XML nightmares — hundreds of lines listing every single .cs file. SDK-style project files are clean.

Ask Claude Code to convert a project file, and it transforms this:

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
  <PropertyGroup>
    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
    <OutputType>Library</OutputType>
    <AssemblyName>MyApp.Core</AssemblyName>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, ...">
      <HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Models\User.cs" />
    <Compile Include="Models\Order.cs" />
    <Compile Include="Services\UserService.cs" />
    <!-- 200 more lines -->
  </ItemGroup>
</Project>

Into this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
</Project>

From 50+ lines to 12. Claude Code handles the packages.config to PackageReference conversion, removes the explicit file includes (SDK-style projects use globbing), and drops the boilerplate imports.


Step 4: Replace deprecated APIs

This is the tedious part of any migration. Framework-specific APIs that don’t exist in modern .NET. Claude Code handles the common patterns well.

HttpContext and System.Web:

// Before: .NET Framework
var userId = HttpContext.Current.Session["UserId"]?.ToString();
var ip = HttpContext.Current.Request.UserHostAddress;
// After: .NET 8 — inject IHttpContextAccessor
public class UserService(IHttpContextAccessor httpContextAccessor)
{
    public string? GetUserId() =>
        httpContextAccessor.HttpContext?.Session.GetString("UserId");

    public string? GetClientIp() =>
        httpContextAccessor.HttpContext?.Connection.RemoteIpAddress?.ToString();
}

ConfigurationManager:

// Before: .NET Framework
var connectionString = ConfigurationManager.ConnectionStrings["DefaultDb"].ConnectionString;
var apiKey = ConfigurationManager.AppSettings["ExternalApiKey"];
// After: .NET 8 — use IConfiguration or options pattern
public class ApiSettings
{
    public string ExternalApiKey { get; set; } = "";
}

// In Program.cs:
builder.Services.Configure<ApiSettings>(builder.Configuration.GetSection("Api"));

Claude Code doesn’t just do search-and-replace. It understands the patterns and rewrites them idiomatically. It’ll suggest the options pattern where appropriate and inject IConfiguration where a quick fix is enough.


Step 5: Migrate dependency injection

If your Framework project uses Ninject, Unity, or Autofac, you have a decision to make. Modern .NET has built-in DI that covers most scenarios.

Claude Code can rewrite your DI registrations:

// Before: Ninject
kernel.Bind<IUserRepository>().To<SqlUserRepository>().InRequestScope();
kernel.Bind<IOrderService>().To<OrderService>().InTransientScope();
kernel.Bind<ICacheService>().To<RedisCacheService>().InSingletonScope();
// After: Built-in Microsoft DI
builder.Services.AddScoped<IUserRepository, SqlUserRepository>();
builder.Services.AddTransient<IOrderService, OrderService>();
builder.Services.AddSingleton<ICacheService, RedisCacheService>();

The lifetime mapping is straightforward: InRequestScope becomes AddScoped, InTransientScope becomes AddTransient, InSingletonScope becomes AddSingleton. Claude Code handles this reliably.

For complex Autofac registrations — modules, decorators, keyed services — it gets trickier. Claude Code can handle most of it, but review carefully. Or just keep Autofac. It works fine with .NET 8.


Step 6: Configuration migration

Moving from web.config XML to appsettings.json is another task Claude Code handles well. Ask it to convert your configuration, and it restructures the data:

{
  "ConnectionStrings": {
    "DefaultDb": "Server=.;Database=MyApp;Trusted_Connection=true"
  },
  "Api": {
    "ExternalApiKey": "your-key-here",
    "Timeout": 30
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

It also generates the corresponding Program.cs setup with the minimal hosting model. No more Startup.cs with ConfigureServices and Configure — just a clean Program.cs.


What Claude Code can’t do

Let me be honest about the limits.

WCF services. If you’re hosting WCF services (not just consuming them), there’s no clean migration path. CoreWCF exists, but it’s a compatibility layer, not a real migration. Claude Code can help you assess which services to rewrite as minimal APIs, but the architectural decisions are on you.

ASP.NET WebForms. There’s no automated path from .aspx pages with code-behind to Razor Pages or Blazor. Claude Code can help rewrite individual pages, but it can’t understand your ViewState-dependent page lifecycle automatically. This is a rewrite, not a migration.

COM interop. If your application calls COM components, Claude Code can identify those dependencies but can’t magically make them work on Linux or in containers. You’ll need to decide: keep Windows, find a .NET alternative, or isolate the COM dependency.

Custom build targets and MSBuild magic. Some Framework projects have elaborate MSBuild customizations. Claude Code handles standard patterns but might miss custom BeforeCompile targets or conditional property groups that do something unexpected.


Realistic expectations

A migration like this isn’t a weekend project. Here’s what I’ve seen in practice:

  • Class libraries with no Framework dependencies: 30 minutes per project with Claude Code.
  • Libraries using ConfigurationManager or System.Web: 1-2 hours per project.
  • ASP.NET MVC projects: A full day, including routing and middleware changes.
  • WCF services: Days to weeks, depending on complexity. Claude Code helps, but this is mostly manual architectural work.

The honest truth: Claude Code turns a six-month migration into a two-month migration. It doesn’t eliminate the work — it eliminates the boring parts. The dependency mapping, the csproj conversions, the API replacements, the DI rewrites. That’s 70% of the effort, and Claude Code handles it well.

The remaining 30% — architectural decisions, testing edge cases, dealing with WCF and WebForms — that’s still on you.


Where to start

Don’t try to migrate everything at once. Pick the smallest, most independent library in your solution. Ask Claude Code to convert it. Build. Run the tests. Fix what breaks.

Then do the next one. And the next one.

Before you know it, half your solution is on .NET 8 and the Framework projects are the exception, not the rule. That’s when the migration stops feeling impossible and starts feeling inevitable.


Facing a .NET Framework migration? Or already in the middle of one? I’d love to hear what you’re dealing with. Reach out via the contact page.