How to instantiate a DbContext in EF Core

75,955

Solution 1

Note


At the time of writing the use of EF Core with the Dependency injection framework wasn't as known as it is now. This answers gives answer to the question from a DI perspective, which at the time, helped out OP.

The other answer provides you a conventional way to instantiate the DbContext using the new operator.


TL;DR, 3 options:

Option 1

Register the DbContext during application configuration:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextPool<BlexzWebDb>(options => 
           options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
}

and use the DI framework to retrieve it:

public class SomeController : Controller
{
    private readonly BlexzWebDb _db;

    //the framework handles this
    public SomeController(BlexzWebDb db)
    {
        _db = db;
    }
}

Option 2

If you are looking for a design-time IdentityDbContext using IOptions<OperationalStoreOptions>, see: Add migration for ApiAuthorizationDbContext from another project - EF Core

Option 3

Or use the new operator and provide the details, see @Qamar Zaman's answer for details.


The long answer, and why DI is a treat

In EF Core it's common to pass some DbContextOptions to the constructor.

So in general, a constructor looks like this:

public BlexzWebDb(DbContextOptions<BlexzWebDb> options) : base(options)

As you can see there, there is no valid overload in the form of a parameter-less constructor:

Thus, this does not work:

using (var db = new BlexzWebDb())

Obviously, you can pass in an Option object in the constructor but there is an alternative. So,

Instead


.Net Core has IoC implemented in it's roots. Okay, this means; you don't create a context, you ask the framework to give you one, based on some rules you defined before.

Example: somewhere you will register your dbcontext, (Startup.cs):

//typical configuration part of .net core
public void ConfigureServices(IServiceCollection services)
{
    //some mvc 
    services.AddMvc();
  
    //hey, options! 
    services.AddDbContextPool<BlexzWebDb>(options => 
           options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
    //...etc

Now the registering part is done, you can retrieve your context from the framework. E.g.: inversion of control through a constructor in your controller:

public class SomeController : Controller
{
    private readonly BlexzWebDb _db;

    //the framework handles this
    public SomeController(BlexzWebDb db)
    {
        _db = db;
    }

    //etc.

why?

So, why not just provide the arguments and new it?

There is nothing wrong with the use of new - there are a lot of scenario's in which it works best.

But, Inversion Of Control is considered to be a good practice. When doing asp dotnet core you're likely to use it quite often because most libraries provide extension methods to use it. If you are not familiar with it, and your research allow it; you should definitely give it a try.

Therefore, instead of providing "just a way to instantiate" the object, I'll try to get you onto this track - inline with the framework. It will save you some hassle afterwards. Besides, otherwise "use an activator's CreateInstance" would just be as valid as an answer ;-)

Some links:

Solution 2

Instantiate new object of DbContext from ConnectionString

var connectionstring = "Connection string";

var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
    optionsBuilder.UseSqlServer(connectionstring);


ApplicationDbContext dbContext = new ApplicationDbContext(optionsBuilder.Options);

// Or you can also instantiate inside using

using(ApplicationDbContext dbContext = new ApplicationDbContext(optionsBuilder.Options))
{
   //...do stuff
}

Solution 3

As addition of @Stefan's answer there is another way to achieve this. You can set db connection string in OnConfiguring method of DbContext class without adding DbContext service in startup.cs.

Setting.cs

public static class Setting
{
    public static string ConnectionString { get; set; }
}

Startup.cs

Setting.ConnectionString = Configuration.GetSection("ConnectionStrings:BlexzDbConnection").Value;

BlexzWebDb.cs

public class BlexzWebDb : DbContext 
{
   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
   {
       if (!optionsBuilder.IsConfigured)
       {
           optionsBuilder.UseSqlServer(Setting.ConnectionString);
       }
    }
}

HomeController.cs

public class HomeController : Controller
{
    private readonly BlexzWebDb db;

    public HomeController()
    {
        this.db = new BlexzWebDb();
    }

    //etc.

Solution 4

Code sample for EF Core 3.1:

public class Test
{
    private readonly IServiceProvider _serviceProvider;

    public Test(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task<RequestResult> Handle(...)
    {
        await using var context = CreateContext();
        ...
    }

    private DocumentContext CreateContext()
    {
        var options = _serviceProvider.GetService<IOptions<DocumentContextOptions>>();
        return new DocumentContext(options);
    }
}
Share:
75,955
john Cogdle
Author by

john Cogdle

Updated on March 09, 2021

Comments

  • john Cogdle
    john Cogdle about 3 years

    I have setup .net core project and db context also. But i cant start using dbContext yet due this error-

    "there is no argument given that corresponds to the required formal parameter 'options'"

    Controller:

    public IActionResult Index()
    {
        using (var db = new BlexzWebDb())
        {
    
        }
        return View();
    }
    

    Dbcontext Code:

    public class BlexzWebDb : DbContext
    {
        public BlexzWebDb(DbContextOptions<BlexzWebDb> options)
           : base(options)
        { }
    
        public DbSet<User> Users { get; set; }
        public DbSet<Role> Roles { get; set; }
        public DbSet<AssignedRole> AssignedRoles { get; set; }
    
    }
    

    error picture attached. Whats the possible fix for that issue? Thanks in advance

    pic