Generic repository in ASP.NET Core without having

2019-01-11 08:57发布

问题:

I have a generic repository in my project. Consider the following controller snippet

public class Lookup1Controller : Controller
{
    readonly MyDbContext _db;

    public Lookup1Controller(MyDbContext dataContext)
    {
        _db = dataContext;
    }

    public async Task<IActionResult> Index()
    {

        IGenericRepository<Lookup1> _repository = new GenericRepository<Lookup1>(_db);
        var lookup1s = await _repository.SelectAll();

        return  View(lookup1s);
    }

I don't see the need to have my Database reference both in my Generic repository as well as each of my controllers.

I refactor it to:

public class Lookup1Controller : Controller
{
    private IGenericRepository<Lookup1> _repository;

    public Lookup1Controller(IGenericRepository<Lookup1> repository)
    {
        _repository = repository;
    }

    public async Task<IActionResult> Index()
    {
        var lookup1s = await _repository.SelectAll();

        return  View(lookup1s);
    }

}

which is much neater and ASP.NET 5 best practice from what I read. but I will get the following error if I access that controller route in my browser:

InvalidOperationException: Unable to resolve service for type 'MyProject.Data.IGenericRepository`1[MyProject.Models.Lookup1]' while attempting to activate 'MyProject.Controllers.Lookup1.

because of I haven't injected the GenericRepository to use the interface.

I add to my Startup.cs an AddScoped line for each and every of my tables in the ConfigureServices method

services.AddScoped<IGenericRepository<Lookup1>,GenericRepository<Lookup1>> ();
services.AddScoped<IGenericRepository<Lookup2>,GenericRepository<Lookup2>> ();
services.AddScoped<IGenericRepository<Lookup3>,GenericRepository<Lookup3>> ();
services.AddScoped<IGenericRepository<Lookup4>,GenericRepository<Lookup4>> ();
etc

so that my code runs without throwing an exception.

However my database has about 100 simple lookup tables. When I look at the above 100 lines of code it just doesn't look right.

It feels like copy and paste code. Each time I add a new table by adding a new model and controller with view my code will compile without giving me an error. But if I run the program and go to that view I could get the controller run error if I forgot to add the AddScoped line to my Startup.cs. Not really good for maintainability.

My question:

  1. Is it really best practice to have a services.AddScoped for each and every lookup table in the ConfigureServices method of Startup.cs?

  2. It is a generic repository so isn't there be a way to write those 100 copy and paste lines in one line?

  3. If not then what is the best practice way to do this using my code?

回答1:

Just use the non-generic registration overloads (The ones where you need to pass the 2 Type objects.) Then provide the open generic types of both your interface and the implementation:

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

In your controller add a dependency for a repository of a specific type (a closed generic type)

public HomeController(IGenericRepository<Lookup1> repository)
{
    ...
}