Search code examples
c#asp.net-coreconstructorentity-framework-core

Is there any better way to add the dbcontext to a Asp.core MVC controller?


In the new MVC Core it seems the standard way to get the context to the controller is by doing this

public class BaseController : Controller
{
    public readonly ReportDBContext _db;
    
    public BaseController(ReportDBContext db)
    {
        _db = db;
    }
}

I can then use

public class HomeController : BaseController
{   
    public HomeController(ReportDBContext db) : base(db) { }
}

To make this a little easier in all other controllers. Normally in Asp.net MVC I can get a context any time by using new ReportDBContext()

Is there a similar way of this now, or do I have to have the context in all controllers in asp.core MVC?


Solution

  • Thanks to @mm8's answer, if you decided to use dependency injection, then you can follow the below mentioned steps.

    Suppose that you have defined your ReportDBContext like this:

    public class ReportDBContext : DbContext
    {
        public DbSet<Sample> Samples { get; set; }
        //...
    
        public ReportDBContext(DbContextOptions<ReportDBContext> options) : base(options) 
        { 
          //...
        }
    }
    

    So you need to config your startup.cs like this:

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            //...What needed
            services.AddDbContext<ReportDBContext>(options => options.UseSqlServer("Connection string to your DB"));
            //...What needed
        }
        //...
     }
    

    So you can easily inject your ReportDBContext to your classes like this(for example inject it to one of your controllers):

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly ReportDBContext _dbContext;
    
        public ValuesController(ReportDBContext dbContext )
        {
            _dbContext = dbContext;
        }
        //...
    }
    

    You can simply inject the ReportDBContext to your BaseController instead of injecting it to every controller in your project too.

    Update 1

    If you do not want to inject the ReportDBContext into each constructor, then you can design your BaseController as follow by using HttpContext.RequestServices:

    public class BaseController : Controller
    {
        protected ReportDBContext DbContext => (ReportDBContext)HttpContext.RequestServices.GetService(typeof(ReportDBContext));
        //...
    }
    
    [Route("api/[controller]")]
    public class ValuesController : BaseController
    {
        //...
    
        [HttpGet]
        public List<Sample> Get() => DbContext.Samples.ToList();
    }
    

    Read more here:

    1. https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
    2. http://www.binaryintellect.net/articles/17ee0ba2-99bb-47f0-ab18-f4fc32f476f8.asp

    You will need to install at least these two NuGet packages too:

    1. Microsoft.EntityFrameworkCore
    2. Microsoft.EntityFrameworkCore.SqlServer (If the database provider is Microsoft SQL Server)