23

Being fairly new to ASP.NET Core 1.0 MVC, I have decided to use a Repository Pattern for an MVC Core app; I'm using a SQL DB for the Data Layer SampleDbContext, and I want to have a Repository class for some of my business Entities. So far I have done the following in thestartup.cs, CustomerController.cs and CustomerRepository.cs files, where a sample Entity is "Customer".

In the ConfigureServices method of the Startup Class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SampleDbContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("SampleDB")));
}

In a Controller:

public class CustomerController : Controller
{

    private SampleDBContext _context;
    private CustomerRepository = new CustomerRepository (new SampleDBContext());

    public CustomerController(SampleDBContext context)
    {
        _context = context;
    }
}

In a Repository:

public class CustomerRepository
{
    private SampleDBContext _context;

    public CustomerRepository(SampleDBContext context)
    {
        _context = context;
    }
}

With this design, I plug in the SampleDbContext as a service in the startup.cs once, and then for each Controller (that receives Dependency Injection) I instantiate a corresponding Repository passing along a new instance of the SampleDbContext. Is this repetitive instantiation of the DB context a good design for a multi-user environment? I suppose I could add each Repository as a service to the startup.cs but that doesn't look nice. Please tell me a good design implementation for my case, or put me in the right track if I'm lost.

1

3 Answers 3

33

You can see simple example how to use repository pattern:

You create repository interface:

using System.Collections.Generic;

namespace TodoApi.Models
{
    public interface ITodoRepository
    {
        void Add(TodoItem item);
        IEnumerable<TodoItem> GetAll();
        TodoItem Find(long key);
        void Remove(long key);
        void Update(TodoItem item);
    }
}

Then implement it:

using System;
using System.Collections.Generic;
using System.Linq;

namespace TodoApi.Models
{
    public class TodoRepository : ITodoRepository
    {
        private readonly TodoContext _context;

        public TodoRepository(TodoContext context)
        {
            _context = context;
            Add(new TodoItem { Name = "Item1" });
        }

        public IEnumerable<TodoItem> GetAll()
        {
            return _context.TodoItems.ToList();
        }

        public void Add(TodoItem item)
        {
            _context.TodoItems.Add(item);
            _context.SaveChanges();
        }

        public TodoItem Find(long key)
        {
            return _context.TodoItems.FirstOrDefault(t => t.Key == key);
        }

        public void Remove(long key)
        {
            var entity = _context.TodoItems.First(t => t.Key == key);
            _context.TodoItems.Remove(entity);
            _context.SaveChanges();
        }

        public void Update(TodoItem item)
        {
            _context.TodoItems.Update(item);
            _context.SaveChanges();
        }
    }
}

Then register in ConfigureServices:

services.AddSingleton<ITodoRepository, TodoRepository>();

Then inject it to Controller:

namespace TodoApi.Controllers
{
    [Route("api/[controller]")]
    public class TodoController : Controller
    {
        public TodoController(ITodoRepository todoItems)
        {
            TodoItems = todoItems;
        }
        public ITodoRepository TodoItems { get; set; }
    }
}
7
  • This is a clear answer to design the Repo pattern, thanks!. If you use the AddSingleton would you have problems on multi-user environments? Commented Feb 21, 2017 at 15:43
  • 1
    @GiancarloSierra, not sure about this, please look at documentation: learn.microsoft.com/en-us/aspnet/core/fundamentals/…
    – Alexan
    Commented Feb 21, 2017 at 16:08
  • 8
    @GiancarloSierra, probably AddScoped will be better for repository.
    – Alexan
    Commented Feb 24, 2017 at 4:33
  • 1
    IN some situation you will receive 'Access to the disposed contex' :(
    – alerya
    Commented Sep 6, 2017 at 6:00
  • 2
    @ruffin, yes, it looks like repository pattern is not needed anymore for ASP.NET Core: stackoverflow.com/questions/48874591/…
    – Alexan
    Commented Feb 23, 2018 at 23:00
2

Some argue that DbContext itself is a repository pattern. If you want to go that route, you can download the sample code at ASP.NET Core and Angular 2.

For example -

public class CustomerController : Controller
{
    private SampleDBContext _context;

    public CustomerController(SampleDBContext context)
    {
        _context = context;
    }

    public async Task<IActionResult> Index(int id)
    {
        var user = _context.Users.Where(i => i.Id == id).FirstOrDefault();
        ...
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SampleDBContext>(options =>
        options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])
        );
}
5
  • 4
    Ya. Some might argue that DbContext follows the Unit of Work pattern :). I think the main reason to implement the repository pattern is to separate your storage framework (i.e. EntityFramework) from the rest of your application. Maybe app wants to store in text files later (no idea why, but hey, crazy decisions get made all the time).
    – Rob Gray
    Commented Feb 21, 2017 at 1:43
  • @Win So in the model of the question, I use the same model as this answer but I pass a new instance on the DbContext to the a repository class for every entity. Stating my question again; Is this repetitive instantiation of the DB context a good design for a multi-user environment? Commented Feb 21, 2017 at 15:43
  • 2
    @GiancarloSierra Do not create new instance of DbContext for every entity. Basically, Controller or CustomerRepository should not create instance of DbContext. Let IoC container taking care of it.
    – Win
    Commented Feb 21, 2017 at 16:15
  • 1
    @Win, the IoC point sounds logical. For that matter I don't see an issue while using the Dependency Injection (DI) on the Controller, as is being received directly, however, how would you use DI to pass the DbContext to the CustomerRepository in the posted scenario? Commented Feb 21, 2017 at 18:43
  • I would argue that add this pattern makes it easier to upgrade to another version update. EF has made many updates over the past few years so upgrading to Version 8 would mean only updating that specific class. Commented Aug 23, 2017 at 12:58
1

I'm not sure its the best method, but I've always created the repository as an interface that the controllers implement.

IRepository.cs:

public interface IRepository
{
     SomeList GetSomeList(string userId);
     Some GetSomeDetail(int someId);
}

DbInterface.cs:

public class DbInterface : IRepository
{
    public SomeList GetSomeList(string userId)
    {

    }

    public Some GetSomeDetail(int someId)
    {

    }
}

SomeList being a datatype that I've defined with all the properties to be displayed on a page as a list. I.e. a list of tasks in a task app. Some being a data type defined which returns the details of a task (so the input would be taskId or such).

Happy to be corrected if this is a bad method.

2
  • Pretty much there, except I think you mean you create a concrete implementation of IRepository, DbInterface that is then injected into your controller. See @Alex's answer.
    – Rob Gray
    Commented Feb 21, 2017 at 1:46
  • Bugger. Forgot some steps. Thanks :)
    – Kris.J
    Commented Feb 21, 2017 at 2:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.