Configuring a DbContext

This article shows basic patterns for configuring a DbContext via a DbContextOptions to connect to a database using a specific EF Core provider and optional behaviors.

Design-time DbContext configuration

EF Core design-time tools such as migrations need to be able to discover and create a working instance of a DbContext type in order to gather details about the application's entity types and how they map to a database schema. This process can be automatic as long as the tool can easily create the DbContext in such a way that it will be configured similarly to how it would be configured at run-time.

While any pattern that provides the necessary configuration information to the DbContext can work at run-time, tools that require using a DbContext at design-time can only work with a limited number of patterns. These are covered in more detail in the Design-Time Context Creation section.

Configuring DbContextOptions

DbContext must have an instance of DbContextOptions in order to perform any work. The DbContextOptions instance carries configuration information such as:

  • The database provider to use, typically selected by invoking a method such as UseSqlServer or UseSqlite. These extension methods require the corresponding provider package, such as Microsoft.EntityFrameworkCore.SqlServer or Microsoft.EntityFrameworkCore.Sqlite. The methods are defined in the Microsoft.EntityFrameworkCore namespace.
  • Any necessary connection string or identifier of the database instance, typically passed as an argument to the provider selection method mentioned above
  • Any provider-level optional behavior selectors, typically also chained inside the call to the provider selection method
  • Any general EF Core behavior selectors, typically chained after or before the provider selector method

The following example configures the DbContextOptions to use the SQL Server provider, a connection contained in the connectionString variable, a provider-level command timeout, and an EF Core behavior selector that makes all queries executed in the DbContext no-tracking by default:

optionsBuilder
    .UseSqlServer(connectionString, providerOptions=>providerOptions.CommandTimeout(60))
    .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

Note

Provider selector methods and other behavior selector methods mentioned above are extension methods on DbContextOptions or provider-specific option classes. In order to have access to these extension methods you may need to have a namespace (typically Microsoft.EntityFrameworkCore) in scope and include additional package dependencies in the project.

The DbContextOptions can be supplied to the DbContext by overriding the OnConfiguring method or externally via a constructor argument.

If both are used, OnConfiguring is applied last and can overwrite options supplied to the constructor argument.

Constructor argument

Context code with constructor:

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    { }

    public DbSet<Blog> Blogs { get; set; }
}

Tip

The base constructor of DbContext also accepts the non-generic version of DbContextOptions, but using the non-generic version is not recommended for applications with multiple context types.

Application code to initialize from constructor argument:

var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");

using (var context = new BloggingContext(optionsBuilder.Options))
{
  // do stuff
}

OnConfiguring

Context code with OnConfiguring:

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=blog.db");
    }
}

Application code to initialize a DbContext that uses OnConfiguring:

using (var context = new BloggingContext())
{
  // do stuff
}

Tip

This approach does not lend itself to testing, unless the tests target the full database.

Using DbContext with dependency injection

EF Core supports using DbContext with a dependency injection container. Your DbContext type can be added to the service container by using the AddDbContext<TContext> method.

AddDbContext<TContext> will make both your DbContext type, TContext, and the corresponding DbContextOptions<TContext> available for injection from the service container.

See more reading below for additional information on dependency injection.

Adding the Dbcontext to dependency injection:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
}

This requires adding a constructor argument to your DbContext type that accepts DbContextOptions<TContext>.

Context code:

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options)
      :base(options)
    { }

    public DbSet<Blog> Blogs { get; set; }
}

Application code (in ASP.NET Core):

public class MyController
{
    private readonly BloggingContext _context;

    public MyController(BloggingContext context)
    {
      _context = context;
    }

    ...
}

Application code (using ServiceProvider directly, less common):

using (var context = serviceProvider.GetService<BloggingContext>())
{
  // do stuff
}

var options = serviceProvider.GetService<DbContextOptions<BloggingContext>>();

More reading