简体   繁体   中英

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?

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://docs.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)

Normally in Asp.net MVC I can get a context any time by using new ReportDBContext ()...

You could do the same, ie create a new context explicitly in the controller, nowadays. There is nothing that stops for you from doing this, except for best practices.

Some of the benfits of using dependency injection is that you can define the lifetime of the dependency in the Startup class and reuse it across all your controllers, and that you can mock away dependencies in your unit tests. Please refer to the docs and this question for more information.

But you certainly don't have to use dependency injection if you don't want to or have a reason not to do so. The compiler won't force to you define a custom constructor that accepts a dependency.

The architecture of ASP.NET Core is built on Dependency Injection. It even has a built-in dependency injection container, but you can also user others like AutoFac or NInject. If you need the DbContext in more than one action, you can use constructor injection, like in your example.

If you need it only once, you can inject it directly into the action method like so:

public IActionResult Get([FromServices]ReportDbContext db) 
{ 
   …
} 

The usage of Dependency Injection makes your code more testable. For your unit tests you could inject a InMemory DbContext.

In my opinion it is even less work than constructing the DbContext yourself. It's done by the framework.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM