microsoft/migrating-ef-dbcontext
> Migrates Entity Framework DbContext registration from Global.asax/Startup to ASP.NET Core dependency injection in Program.cs. Handles both EF6 (classic Entity Framework) and EF Core patterns including connection string migration, DI registration, and database initializer/seeding migration. Use when upgrading ASP.NET to ASP.NET Core projects that use DbContext, Database.SetInitializer, or connection strings in web.config. Also triggers for "migrate DbContext", "register DbContext in DI", "move connection string to appsettings.json", or "convert EF6 to EF Core".
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill migrating-ef-dbcontext
Migrates DbContext initialization from legacy ASP.NET patterns (Global.asax, Startup.cs) to ASP.NET Core DI in Program.cs. The registration pattern differs between EF6 and EF Core — this skill handles both, including the decision point when a project uses both simultaneously.
Verify the project uses Entity Framework before proceeding. Search for DbContext subclasses in the codebase and check NuGet references for EntityFramework or Microsoft.EntityFrameworkCore. If neither is found, skip and inform the user.
When both EntityFramework and Microsoft.EntityFrameworkCore packages are present, pause and ask the user which to use for main database logic. Common scenarios:
Record the user's choice — it determines the registration pattern in Steps 3 and 5.
Track progress through these steps:
Migration Progress:
- [ ] Step 1: Find DbContext classes and connection strings
- [ ] Step 2: Update DbContext constructors
- [ ] Step 3: Register DbContext in Program.cs
- [ ] Step 4: Replace direct instantiations with DI
- [ ] Step 5: Migrate database initialization and seeding
Locate all DbContext subclasses — exclude IdentityDbContext subclasses (handled separately by identity migration). For each, find the connection string name passed to the base constructor.
appsettings.json under ConnectionStrings with a descriptive key, then reference that key going forward"name=MyDb") → Copy the matching entry from web.config/app.config to appsettings.json under ConnectionStrings, preserving the same keyModify constructors to accept caller-provided configuration instead of hardcoded connection string names. This enables DI registration in the next step.
EF6 — accept connection string parameter:
public class MyDBContext : DbContext
{
public MyDBContext(string connectionString) : base(connectionString)
{
}
}
EF Core — accept DbContextOptions:
public class MyDBContext : DbContext
{
public MyDBContext(DbContextOptions<MyDBContext> options) : base(options)
{
}
}
Registration differs by EF version because EF Core has built-in DI support via AddDbContext, while EF6 requires manual scoped registration.
EF Core:
builder.Services.AddDbContext<MyDBContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MyConnectionStringName")));
EF6:
builder.Services.AddScoped<MyDBContext>(provider =>
new MyDBContext("name=MyConnectionStringName"));
Add any required using statements (e.g., Microsoft.EntityFrameworkCore for EF Core).
Find all new MyDBContext() calls and refactor to constructor injection. Direct instantiation bypasses the DI-configured connection string and lifetime management.
Before:
public class MyService
{
public void DoWork()
{
using (var context = new MyDBContext())
{
// Use context
}
}
}
After:
public class MyService
{
private readonly MyDBContext _context;
public MyService(MyDBContext context)
{
_context = context;
}
public void DoWork()
{
// Use _context (lifetime managed by DI container)
}
}
Search for Database.SetInitializer calls and move initialization logic to Program.cs. Register any initializer dependencies in the DI container, including transitive dependencies.
EF6 — Preserve the original initialization pattern:
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
Database.SetInitializer(services.GetRequiredService<MyInitializer>());
}
EF Core — Replace initializers with migrations. EF Core does not support Database.SetInitializer; refactor old initializers (e.g., CreateDatabaseIfNotExists, DropCreateDatabaseIfModelChanges) into EF Core migrations and seed methods:
using (var scope = app.Services.CreateScope())
{
var myContext = scope.ServiceProvider.GetRequiredService<MyDBContext>();
myContext.Database.Migrate();
MyDBContextSeed.Seed(myContext);
}
Remove the original Database.SetInitializer calls after migration.
| Aspect | EF6 | EF Core |
|--------|-----|---------|
| DI registration | AddScoped<T>(provider => new T("name=...")) | AddDbContext<T>(options => ...) |
| DB initialization | Database.SetInitializer(...) | context.Database.Migrate() |
| Connection string | "name=ConnectionStringName" format | Configuration.GetConnectionString(...) |
| Initializers | CreateDatabaseIfNotExists, DropCreateDatabaseIfModelChanges | Migrations-based approach |
web.config/app.config to appsettings.jsonnew DbContext() instantiations replaced with constructor injectionDatabase.SetInitializer calls removedTake microsoft/migrating-ef-dbcontext from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.