In an ASP.NET Core application, we typically use EF Core to interact with a database for data persistence. To create and apply migrations, EF Core requires a DbContext instance. Depending on your project setup, EF Core can obtain this DbContext in several ways. Below are three common approaches, along with their features, limitations, and best-use scenarios.

1. Using IDesignTimeDbContextFactory<TContext>

This is the highest-priority approach.

When a migration command is executed, EF Core first checks for a class that implements IDesignTimeDbContextFactory<TContext>. If it finds one, it uses it to create the DbContext and does not check any other configuration. If the factory throws an error, the migration fails immediately.

Features

Example: Basic Setup

namespace TestDesignTimeDataContextFactory.Data
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions options) : base(options) { }
    }
}

internal class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
    public ApplicationDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
        optionsBuilder.UseSqlServer("Your_Connection_String_Here");

        return new ApplicationDbContext(optionsBuilder.Options);
    }
}

Example: Detailed Implementation

namespace TestDesignTimeDataContextFactory.Data
{
    internal class ApplicationDbContext_textDCFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var basePath = Directory.GetCurrentDirectory();

            var configuration = new ConfigurationBuilder()
                .SetBasePath(basePath)
                .AddJsonFile("appsettings.json", false)
                .AddJsonFile("appsettings.Development.json", true)
                .Build();

            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));

            var context = new ApplicationDbContext(optionsBuilder.Options);

            try
            {
                var canConnect = context.Database.CanConnect();
                Console.WriteLine($">>> Can connect to DB: {canConnect}");
            }
            catch (Exception ex)
            {
                Console.WriteLine(">>> DB connection failed");
                Console.WriteLine(ex.Message);
                throw;
            }

            return context;
        }
    }
}

When to Use

2. Configuring DbContext in Program.cs or Startup.cs

This is the most commonly used approach.

If EF Core does not find a design-time factory, it attempts to resolve the DbContext from the startup project, using dependency injection.

// Program.cs or Startup.cs
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    { }
}

Features

Limitations

Important Note

When EF Core builds the application at design time, it resolves all registered services, even those unrelated to the DbContext. If any service fails, the migration will fail. This dependency on the successful build of the app is why using IDesignTimeDbContextFactory<TContext> is generally safer for migrations.

3. Using the OnConfiguring Method (Fallback)

OnConfiguring provides a fallback mechanism. It configures the DbContext only if no other configuration has been applied.

namespace ConnectDatabseWithEFCore.Data
{
    public class ApplicationDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                var configuration = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", false)
                    .Build();

                optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
            }
        }
    }
}

Features

When to Use

When to Avoid

Conclusion