Blog Post

Apps on Azure Blog
5 MIN READ

From "Maybe Next Quarter" to "Running Before Lunch" on Container Apps - Modernizing Legacy .NET App

Jan-Kalis's avatar
Jan-Kalis
Icon for Microsoft rankMicrosoft
Feb 18, 2026

The GitHub Copilot app modernization didn't just improve incrementally. The gap between "assessment" and "done" collapsed. A year ago, knowing what to do and being able to do it were very different things. Now they're almost the same step.

In early 2025, we wanted to modernize Jon Galloway's MVC Music Store — a classic ASP.NET MVC 5 app running on .NET Framework 4.8 with Entity Framework 6. The goal was straightforward: address vulnerabilities, enable managed identity, and deploy to Azure Container Apps and Azure SQL. No more plaintext connection strings. No more passwords in config files.

 

We hit a wall immediately.

Entity Framework on .NET Framework did not support Azure.Identity or DefaultAzureCredential. We just could not add a NuGet package and call it done — we’d need EF Core, which means modern .NET - and rewriting the data layer, the identity system, the startup pipeline, the views. The engineering team estimated one week of dedicated developer work. As a product manager without extensive .NET modernization experience, I wasn't able to complete it quickly on my own, so the project was placed in the backlog.

This was before the GitHub Copilot "Agent" mode, the GitHub Copilot app modernization (a specialized agent with skills for modernization) existed but only offered assessment — it could tell you what needed to change, but couldn't make the end to end changes for you.

Fast-forward one year. The full modernization agent is available. I sat down with the same app and the same goal. A few hours later, it was running on .NET 10 on Azure Container Apps with managed identity, Key Vault integration, and zero plaintext credentials. Thank you GitHub Copilot app modernization!

And while we were on it – GitHub Copilot helped to modernize the experience as well, built more tests and generated more synthetic data for testing.

 

Why Azure Container Apps?

Azure Container Apps is an ideal deployment target for this modernized MVC Music Store application because it provides a serverless, fully managed container hosting environment. It abstracts away infrastructure management while natively supporting the key security and operational features this project required. It pairs naturally with infrastructure-as-code deployments, and its per-second billing on a consumption plan keeps costs minimal for a lightweight web app like this, eliminating the overhead of managing Kubernetes clusters while still giving you the container portability that modern .NET apps benefit from.

That is why I asked Copilot to modernize to Azure Container Apps - here's how it went -

Phase 1: Assessment

GitHub Copilot App Modernization started by analyzing the codebase and producing a detailed assessment:

  • Framework gap analysis — .NET Framework 4.0 → .NET 10, identifying every breaking change
  • Dependency inventory — Entity Framework 6 (not EF Core), MVC 5 references, System.Web dependencies
  • Security findings — plaintext SQL connection strings in Web.config, no managed identity support
  • API surface changes — Global.asax → Program.cs minimal hosting, System.Web.Mvc → Microsoft.AspNetCore.Mvc

The assessment is not a generic checklist. It reads your code — your controllers, your DbContext, your views — and maps a concrete modernization path. For this app, the key finding was clear: EF 6 on .NET Framework cannot support DefaultAzureCredential. The entire data layer needs to move to EF Core on modern .NET to unlock passwordless authentication.

Phase 2: Code & Dependency Modernization

This is where last year's experience ended and this year's began. The agent performed the actual modernization:

Project structure:

  • .csproj converted from legacy XML format to SDK-style targeting net10.0
  • Global.asax replaced with Program.cs using minimal hosting
  • packages.config → NuGet PackageReference entries

Data layer (the hard part):

  • Entity Framework 6 → EF Core with Microsoft.EntityFrameworkCore.SqlServer
  • DbContext rewritten with OnModelCreating fluent configuration
  • System.Data.Entity → Microsoft.EntityFrameworkCore namespace throughout
  • EF Core modernization generated from scratch
  • Database seeding moved to a proper DbSeeder pattern with MigrateAsync()

Identity:

  • ASP.NET Membership → ASP.NET Core Identity with ApplicationUser, ApplicationDbContext
  • Cookie authentication configured through ConfigureApplicationCookie

Security (the whole trigger for this modernization):

  • Azure.Identity + DefaultAzureCredential integrated in Program.cs
  • Azure Key Vault configuration provider added via Azure.Extensions.AspNetCore.Configuration.Secrets
  • Connection strings use Authentication=Active Directory Default — no passwords anywhere
  • Application Insights wired through OpenTelemetry

Views:

  • Razor views updated from MVC 5 helpers to ASP.NET Core Tag Helpers and conventions
  • _Layout.cshtml and all partials migrated

The code changes touched every layer of the application. This is not a find-and-replace — it's a structural rewrite that maintains functional equivalence.

Phase 3: Local Testing

After modernization, the app builds, runs locally, and connects to a local SQL Server (or SQL in a container). EF Core modernizations apply cleanly, the seed data loads, and you can browse albums, add to cart, and check out. The identity system works. The Key Vault integration gracefully skips when KeyVaultName isn't configured — meaning local dev and Azure use the same Program.cs with zero code branches.

Phase 4: AZD UP and Deployment to Azure

The agent also generates the deployment infrastructure:

  • azure.yaml — AZD service definition pointing to the Dockerfile, targeting Azure Container Apps
  • Dockerfile — Multi-stage build using mcr.microsoft.com/dotnet/sdk:10.0 and aspnet:10.0
  • infra/main.bicep — Full IaaC including:
    • Azure Container Apps with system + user-assigned managed identity
    • Azure SQL Server with Azure AD-only authentication (no SQL auth)
    • Azure Key Vault with RBAC, Secrets Officer role for the managed identity
    • Container Registry with ACR Pull role assignment
    • Application Insights + Log Analytics
    • All connection strings injected as Container App secrets — using Active Directory Default, not passwords

One command:

AZD UP

Provisions everything, builds the container, pushes to ACR, deploys to Container Apps. The app starts, runs MigrateAsync() on first boot, seeds the database, and serves traffic. Managed identity handles all auth to SQL and Key Vault. No credentials stored anywhere.

What Changed in a Year

 

Early 2025

Now

Assessment

Available

Available

Automated code modernization

Semi-manual

✅ Full modernization agent

Infrastructure generation

Semi-manual

✅ Bicep + AZD generated

Time to complete

Weeks

✅ Hours

The technology didn't just improve incrementally. The gap between "assessment" and "done" collapsed. A year ago, knowing what to do and being able to do it were very different things. Now they're the same step.

 

Who This Is For

If you have a .NET Framework app sitting on a backlog because "the modernization is too expensive" — revisit that assumption. The process changed. GitHub Copilot app modernization helps you rewrite your data layer, generates your infrastructure, and gets you to azd up. It can help you generate tests to increase your code coverage. If you have some feature requests – or – if you want to further optimize the code for scale – bring your requirements or logs or profile traces, you can take care of all of that during the modernization process.

MVC Music Store went from .NET Framework 4.0 with Entity Framework 6 and plaintext SQL credentials to .NET 10 on Azure Container Apps with managed identity, Key Vault, and zero secrets in code. In an afternoon.

That backlog item might be a lunch break now 😊. Really. Find your legacy apps and try it yourself.

 

Next steps

  1. Modernize your .Net or Java apps with GitHub Copilot app modernization – https://aka.ms/ghcp-appmod
  2. Open your legacy application in Visual Studio or Visual Studio Code to start the process
  3. Deploy to Azure Container Apps https://aka.ms/aca/start
Updated Feb 18, 2026
Version 1.0
No CommentsBe the first to comment