scv
scv

Reputation: 363

Getting dependency injection to work for Entity Framework Core outside of a Razor .cs page

This is for ASP.Net Core 2.1 using Razor with Entity Framework Core.

I think the question is how to define ReadData in ConfigureServices method?

Have tried to look at this question DbContext Dependency Injection outside of MVC project, but still cannot get code to work.

Trying to set up database access with Entity Framework Core through another class other than the Razor page.

In the Startup class in the ConfigureServices method we have this (I think this sets up the dependency injection for the Constructor in the Razor pages .cs):

services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 

//Add Dependency Injection references
services.AddScoped<IReadData, ReadData>();

This is a Razor .cs page and it works with the Constructor; however, we would want to separate the db look up into another class called ReadData.

public class MyPageModel : PageModel
{
    private readonly MyProject.Data.AppDbContext _context;
    private readonly ReadData readData = new ReadData();

    public MyPageModel(MyProject.Data.AppDbContext context)
    {
        _context = context;
    }

    public IList<Car> Cars { get;set; }

    public async Task OnGetAsync()
    {
        var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
        Prayer = await readData.FetchCars(userName);
    }
}

Here's the ReadData class:

public class ReadData : IReadData
{
    private readonly MyProject.Data.AppDbContext _context;

    public ReadData(MyProject.Data.AppDbContext context)
    {
        this._context = context;
    }

    public async Task<IList<Car>> FetchCars(string carOwner)
    {
        var cars =  _context.Cars.Where(p => p.Owner == carOwner);
        return await Task.FromResult(cars.ToList());
    }
}

The dependency injection that works on the Razor .cs pages will not work here. For example, in MyPageModel for this line:

private readonly ReadData readData = new ReadData();

it complains that a parameter is not assigned for the required parameter for ReadData class.

BUT, in ReadData if we add chaining constructor like this:

public ReadData() : this(new MyProject.Data.AppDbContext()) { }

we get an error:

InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.

How do we get dependency injection to work for Entity Framework Core in the ReadData class?

Upvotes: 0

Views: 940

Answers (2)

Ahmed Ghoniem
Ahmed Ghoniem

Reputation: 681

Just inject IReadData on the constructor of MyPageModel

public class MyPageModel : PageModel
{
    private readonly MyProject.Data.AppDbContext _context;
    private readonly IReadData _readData ;

    public MyPageModel(IReadData readData)
    {
        _readData = readData;
    }

    public async Task OnGetAsync()
    {
        var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
       var Prayer = await _readData.FetchCars(userName);
    }
}

Don't create instance of ReadData

ReadData readData = new ReadData();

let DI container resolve your dependencies as you registered services.AddScoped<IReadData, ReadData>();

Upvotes: 1

DavidG
DavidG

Reputation: 118937

Your ReadData class should take a context in it's constructor:

public ReadData(MyProject.Data.AppDbContext context)
{

}

And now you only need to inject this class into your model:

public class MyPageModel : PageModel
{
    private readonly IReadData _readData ;

    public MyPageModel(IReadData readData)
    {
        _readData = readData;
    }

    public async Task OnGetAsync()
    {
        var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
       var Prayer = await _readData.FetchCars(userName);
    }
}

Let the DI container deal with creating your objects for you.

Upvotes: 4

Related Questions