24

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; }
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

This is a clear answer to design the Repo pattern, thanks!. If you use the AddSingleton would you have problems on multi-user environments?
@GiancarloSierra, not sure about this, please look at documentation: learn.microsoft.com/en-us/aspnet/core/fundamentals/…
@GiancarloSierra, probably AddScoped will be better for repository.
IN some situation you will receive 'Access to the disposed contex' :(
@ruffin, yes, it looks like repository pattern is not needed anymore for ASP.NET Core: stackoverflow.com/questions/48874591/…
|
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 Comments

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).
@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?
@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, 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?
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.
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 Comments

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.
Bugger. Forgot some steps. Thanks :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.