I'm using ASP 5, MVC 6, and Entity Framework 7 to create a small website (foreseeably less than 100 registered users and 10,000 monthly visitors). I'm a rookie programmer with under 1000 hours of combined experience and research.
I've got a lot of questions at the bottom, but in general I'd just like to be sure I understand the repository pattern and why it could be beneficial to me. Right now I'm only using it because I read 'it's good idea' from multiple sources, and because it seems to make sense for organizational purposes.
After I read about the Repository Pattern. I took some ideas from these sources:
Microsoft, Code Guru, DotNetCurry
I created a generic interface IRepository:
interface IRepository<TEntity,in TPKey> where TEntity : class
{
IEnumerable<TEntity> GetAll();
TEntity Get(TPKey id);
void Insert(TEntity ent);
void Update(TEntity ent);
void Delete(TEntity ent);
}
Then I created a specific Repository for one of my entities:
public class CollegeRepository : IRepository<Models.College, int>
{
private ApplicationDbContext _context = null;
public CollegeRepository()
{
_context = new ApplicationDbContext();
}
public CollegeRepository(ApplicationDbContext context)
{
this._context = context;
}
public College Get(int id)
{
return _context.Colleges.Where(c => c.CollegeID == id).FirstOrDefault();
}
public IEnumerable<College> GetAll()
{
return _context.Colleges.ToList();
}
public void Insert(College college)
{
_context.Colleges.Add(college);
}
public void Update(College college)
{
_context.Update(college);
}
public void Delete(College college)
{
_context.Colleges.Remove(college);
}
Inside of my CollegesController I originally did something like this:
// POST: Schools/Edit/5
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public IActionResult Edit(College school, IFormFile logo)
{
if (ModelState.IsValid)
{
if (logo != null)
{
byte[] imgBytes = new byte[logo.Length];
logo.OpenReadStream().Read(imgBytes, 0, (int)logo.Length);
school.Logo = imgBytes;
_context.Update(school);
}
else
{
// Mark the logo as unmodified so the data is not lost.
_context.Update(school).Property(s => s.Logo).IsModified = false;
}
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(school);
}
Then changed to this:
// POST: Schools/Edit/5
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public IActionResult Edit(College school, IFormFile logo)
{
if (ModelState.IsValid)
{
collegeRepo.Update(school, logo);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(school);
}
And modified the specific repository to add an Update overload:
public class CollegeRepository : IRepository<Models.College, int>
{
public void Update(College college)
{
_context.Update(college);
}
public void Update(College college, IFormFile logo)
{
if (logo != null)
{
byte[] imgBytes = new byte[logo.Length];
logo.OpenReadStream().Read(imgBytes, 0, (int)logo.Length);
college.Logo = imgBytes;
_context.Update(college);
}
else
{
// Mark the logo as unmodified so the data is not lost.
_context.Update(college).Property(s => s.Logo).IsModified = false;
}
}
}
It seems I have successfully separated my logic from my controller. Is this the idea behind the repository pattern? Have I used it successfully in this example? To what degree am I unsuccessful?
I was reading, after I did all this, that the repository pattern is not all that useful for projects which will only use (and may only ever use) 1 data source (like mine), but that there should always be some sort of Unit of Work class to keep logic out of controllers (I vaguely understand what it means to have a unit of work, but answers that touch on this would be appreciated as well).
I've also read that the repository pattern is helpful for reducing duplicate code. I can't see far enough ahead, with my inexperienced eyes, to think that I might use any of my controller code again. What are some common MVC scenarios where you've seen (could see) code duplication occur without the repository pattern?
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
If you don't care about the code I wrote and just want to have a discussion about abstracting existing abstractions... skip to the last 3 paragraphs.
I was introduced to the idea of Repositories and the Unit Of Work on top of Entity Framework via a Pluralsight lesson I was watching. I also stubmled upon Microsoft's own page detailing this process: http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
So I decided to try it out. I set out to write my own Unit Of Work class with generic Repositories on top of Entity Framework, making absolutely everything along the way utilize interfaces so I could inject my own mocks for testing.
First things first, for this exercise I chose to make a simple Blog application.
So I started with the DbContext. Gotta make sure I use an interface!
public interface ISimpleBlogContext : IDisposable
{
IDbSet<Blog> Blogs { get; }
IDbSet<Post> Posts { get; }
void SaveChanges();
IDbSet<T> Set<T>() where T : class;
DbEntityEntry Entry<T>(T entity) where T : class;
}
I'm sure everybody knows what the IDbSets are for, but the SaveChanges, Set, and Entry methods might look a bit out of place. Don't worry, we'll get to those later.
So now I hooked up my interface into an actual concrete DbContext :
public class SimpleBlogContext : DbContext, ISimpleBlogContext
{
public SimpleBlogContext() {
Database.SetInitializer<SimpleBlogContext>(new DropCreateDatabaseAlways<SimpleBlogContext>());
}
public IDbSet<Blog> Blogs { get; set; }
public IDbSet<Post> Posts { get; set; }
public DbEntityEntry Entry<T>(T entity) where T : class
{
return Entry<T>(entity);
}
void ISimpleBlogContext.SaveChanges()
{
SaveChanges();
}
IDbSet<T> ISimpleBlogContext.Set<T>()
{
return Set<T>();
}
The database initializer is just ensuring that for this test application the database is dropped and recreated each time I run the app. This was just an exercise and not a real app after all. You can see the SaveChanges, Set, and Entry methods implemented here, and they're all nothing more than wrappers for the DbContext methods of the same name.
So now on to the repositories...
I wasn't going to re-write virtually the same repository code for every entity I might add to my application (although in this case I'll only wind up using one repository), so I made a generic repository. Don't skip the interface!
public interface IGenericRepository<T>
where T : class
{
IEnumerable<T> GetAll();
T GetById(object id);
IEnumerable<T> GetByExpression(Expression<Func<T, bool>> expression);
void Add(T entity);
void Delete(T entity);
void Update(T entity);
}
and the concrete version... (notice I'm using my ISimpleBlogContext here instead of a concrete DbContext class because I want to be able to test all the things. Also, now you know why I had to write those Set, Entry, and SaveChanges methods in my ISimpleBlogContext interface)
public class GenericRepository<T> : IGenericRepository<T>
where T : class
{
public GenericRepository(ISimpleBlogContext context)
{
this.context = context;
}
private ISimpleBlogContext context;
public void Add(T entity)
{
context.Set<T>().Add(entity);
}
public void Delete(T entity)
{
context.Set<T>().Remove(entity);
}
public IEnumerable<T> GetAll()
{
return context.Set<T>().ToList<T>();
}
public IEnumerable<T> GetByExpression(Expression<Func<T, bool>> expression)
{
return context.Set<T>().Where<T>(expression).ToList<T>();
}
public T GetById(object id)
{
return context.Set<T>().Find(id);
}
public void Update(T entity)
{
context.Entry(entity).State = EntityState.Modified;
}
}
And now finally, the Unit Of Work class
public class UnitOfWork : IDisposable
{
public void Dispose()
{
if (context != null)
{
context.Dispose();
context = null;
}
}
public UnitOfWork()
{
context = new SimpleBlogContext();
}
public UnitOfWork(ISimpleBlogContext context)
{
this.context = context;
}
private ISimpleBlogContext context;
public GenericRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
return new GenericRepository<TEntity>(context);
}
public void Save()
{
context.SaveChanges();
}
}
I'm still allowing an ISimpleBlogContext to be passed in via the overloaded constructor, but the default constructor is where we finally get our concrete SimpleBlogContext DbContext from.
So now I just have to test all this. So I wrote a simple Console application which does nothing more than generate a couple of fake blogs with a couple of fake posts and save them using the Unit Of Work class. Then it loops the blogs and posts and prints them out so I can verify that they were actually saved to the database.
P.S. Jake is my dog in case you're wondering about the barking...
class Program
{
static void Main(string[] args)
{
UnitOfWork unitOfWork = new UnitOfWork();
GenericRepository<Blog> blogRepository = unitOfWork.GetRepository<Blog>();
Blog paulsBlog = new Blog()
{
Author = "Paul",
Posts = new List<Post>()
{
new Post()
{
Title = "My First Post",
Body = "This is my first post"
},
new Post()
{
Title = "My Second Post",
Body = "This is my second post"
}
}
};
Blog jakesBlog = new Blog()
{
Author = "Jake",
Posts = new List<Post>()
{
new Post()
{
Title = "Dog thoughts",
Body = "Bark bark bark"
},
new Post()
{
Title = "I like barking",
Body = "Bark bark bark"
}
}
};
blogRepository.Add(paulsBlog);
blogRepository.Add(jakesBlog);
unitOfWork.Save();
List<Blog> blogs = blogRepository.GetAll() as List<Blog>;
foreach (Blog blog in blogs)
{
System.Console.WriteLine("ID: {0}, Author: {1}\n", blog.Id, blog.Author);
if (blog.Posts != null && blog.Posts.Count > 0)
{
foreach (Post post in blog.Posts)
{
System.Console.WriteLine("Posted at: {0}, Title: {1}, Body: {2}", post.PostTime, post.Title, post.Body);
}
}
else
{
System.Console.WriteLine("No posts");
}
System.Console.WriteLine("\n");
}
}
}
It works. Yay!
My question, however, is simply... what did I gain exactly by doing any of this?
Isn't DbContext already a Unit Of Work and DbSet is already a repository? It seems all I did was write a really elaborate wrapper for both of those things with no added functionality at all. You might say that it's more test-friendly since everything is using interfaces, but with mocking frameworks like Moq it's already possible to mock a DbSets and DbContexts. My repositories are generic so there is literally zero functionality that is specific to business logic. The Unit Of Work class is just a wrapper for DbContext and the generic Repositories are just wrappers for DbSet.
Can somebody explain to me why anybody would do this? I watched a ~4 hour Pluralsight lesson on this, plus went through all the trouble of actually doing it myself, and I still don't get it.
I did the same thin recently and I believe you gain the flexibility of testing your code without requiring actual access to a SQL database.
I have read all sorts of posts on this subject but couldn't find the answer to my question.
The general consensus is that I should be creating a context for 1 unit of work (say 1 web page). I have enclosed every method in my Database.cs (see below) with 'using' hence to me - that implies that each time a method from this class is called - a context is created. So if I was to call 2 Methods from Database.cs from the same Action in the HomeController.cs - would that mean that 2 contexts are created?
Would it not be better to declare a private field inside Database.cs like so:
private Entities db = new Entities()
And have each method within the Database.cs class access it? Which approach is the best?
My current implementation (I'm only going to include the method Verify but there are many methods in the Database class):
HomeController.cs
[AllowAnonymous]
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
Database.cs
public class Database : IDatabase
{
... some other methods ...
public bool VerifyUser(string verificationHash)
{
using (Entities db = new Entities())
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
}
}
db.VerifyUser(..) - this is a call to a stored procedure
Yes that means there are two instances of DbContext.
The better is to have one instance of DbContext in your Database class and use this instance in all your methods.
public class Database : IDatabase, IDisposeable
{
private Entities db;
public Database()
{
db = new Entities()
}
... some other methods ...
public bool VerifyUser(string verificationHash)
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
public void Dispose()
{
db.Dispose()
}
}
Then when you finish from Database instance you dispose it and it will dispose the DbContext
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
using(this.Database)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
}
BTW: you may prefer to dispose your resources at the controller level. In that case, you don't need to add using statement in your actions
e.g. add this to your controller:
protected override void Dispose(bool disposing)
{
this.Database.Dispose();
base.Dispose(disposing);
}
Yes in your design DbContext created and disposed in every method calls.
Actually, it is not a good solution to put all database operations to a class and create DbContext over and over again. You probably have a problem in future with that class. It might have hundred methods in time and so it is hard to maintain and all entities are not related with each other semantically so it may cause confusion. I think it is a better solution to seperate entity types into classes. For example, you have an users, projects, departments. If we apply my solution to these entities then the uml class diagram will be like this.
All repositories takes a reference to DbContext. It is called Dependency Injection. It means that dbcontext is instantiated once and passes its reference through necessary repositories so there are no context re-creation. Also there is a generic repository which you can put standard procedures.
So you can use repositories like this.
[HttpGet]
public ActionResult Verify(string id){
using(var context = new DbContext())
{
var userRepo = new UserRepository(context);
//Department repository can be used over the same context.
var departmentRepo = new DepartmentRepository(context);
if(userRepo.verifyUser(id)){
return View();
}
}
}
I'm currently working on my exam project in ASP.NET MVC 5 (C#).
My problem is one of my controllers, which is heavily relying on the authorize roles attribute to make sure people have a certain role and thereby access to the various functions in the controller. It was working fine, right until I wanted to use dependency injection through the constructor... it seems after I installed ninject for mvc3, set up the bind and made the constructor accepting the interface in the controller. That it just ignores all authorize tags? I know it's not syntax errors because nothing is different in the controller, except the new constructor. This seems to have no effect on the account controller though so I have to presume Ninject is messing things up.
Everyone can do everything they want and run all methods in the controller since I set it up for ninject and I simply don't get it?
Can anyone help or know of this issue and any steps to take to fix it?
I have to turn in the project monday so I was hoping some guru could enlighten me relatively fast on this issue. A google search tells me Ninject doesn't work with the attribute is that true? If it is I'm pretty screwed.
Well I basically added this to the NinjectWebCommon's "RegisterServices" method:
kernel.Bind<IChildRepository>().To<ChildRepository>();
(I'm making a site for an institution that watches kids after school etc. the childcontroller controls the management of "children" created in the system).
private readonly IChildRepository _childRepository;
public ChildController(IChildRepository childRepository)
{
_childRepository = childRepository;
}
This is my repository class:
public class ChildRepository : IChildRepository
{
ChildContext context = new ChildContext();
public IQueryable<Child> All
{
get { return context.Children; }
}
public IQueryable<Child> AllIncluding(params Expression<Func<Child, object>>[] includeProperties)
{
IQueryable<Child> query = context.Children;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public Child Find(int id)
{
return context.Children.Find(id);
}
public void InsertOrUpdate(Child child)
{
if (child.ChildId == default(int))
{
context.Children.Add(child);
}
else
{
context.Entry(child).State = System.Data.Entity.EntityState.Modified;
}
}
public void Delete(int id)
{
var child = context.Children.Find(id);
context.Children.Remove(child);
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
And my repo interface:
public interface IChildRepository : IDisposable
{
IQueryable<Child> All { get; }
IQueryable<Child> AllIncluding(params Expression<Func<Child, object>>[] includeProperties);
Child Find(int id);
void InsertOrUpdate(Child child);
void Delete(int id);
void Save();
}
This is the index method in the controller method to show you how I'm using authorize:
[Authorize(Roles = "Admin, CanEdit")]
public ActionResult Index()
{
return View(_childRepository.All.ToList());
}
How it works now? You can access the childcontroller views and all the other methods besides index without even being logged into the system?
I found the solution to the problem by googling, apparently adding this line to the registerservices method solves the entire issue.
kernel.Bind<IFilterProvider>().To<FilterAttributeFilterProvider>();
Got it from this guy which I love right now:
http://pieterderycke.wordpress.com/2012/03/01/using-asp-net-filters-with-the-ninject-depencency-resolver/
Thought I would answer the question myself so if others run into the same issue they can make it work!
I've just started programming in .NET and I'm having some problems with implementing dependency injection (using Ninject).
I'm creating some sort of catering application where user can browse towns, in towns browse restaurants and in restaurants browse food.
I'm using UnitOfWork and repository pattern where for example I access town by id like this:
_unitOfWork.TownRepository.GetByID(id);
Now I started implementing services into application and I have encountered need for dependency injection.
I have created ITownService, IRestaurantService and IFoodService (since I've TownRepository, RestaurantRepository and FoodRepository in my UnitOfWork).
Sample look of TownService:
public class TownService : ITownService
{
// initialize UnitOfWork
private IUnitOfWork _unitOfWork;
public TownService()
: this(new UnitOfWork())
{
}
public TownService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public Town GetByID(object id)
{
return _unitOfWork.TownRepository.GetByID(id);
}
public IEnumerable<Town> GetAll()
{
return _unitOfWork.TownRepository.Get();
}
public bool Insert(Town town)
{
// validation logic
if (!ValidateTown(town))
return false;
try
{
_unitOfWork.TownRepository.Insert(town);
_unitOfWork.Save();
}
catch
{
return false;
}
return true;
}
public bool Delete(object id)
{
try
{
_unitOfWork.TownRepository.Delete(id);
_unitOfWork.Save();
}
catch
{
return false;
}
return true;
}
public bool Update(Town townToUpdate)
{
// validation logic
if (!ValidateTown(townToUpdate))
return false;
try
{
_unitOfWork.TownRepository.Update(townToUpdate);
_unitOfWork.Save();
}
catch
{
return false;
}
return true;
}
}
I haven't implemented FoodService and RestaurantService yet, but they should be similar with of course some additinal methods exepct this that I have. For example in RestaurantService I might have public Restaurant GetRestaurantsInTown(Town town){} or something like that.
I hope that you got the feel of application a bit. Now lets back to Ninject.
In my TownController I would have something like this:
public class TownController : Controller
{
private ITownService _townService;
public TownController(ITownService townService)
{
_townService = townService;
}
}
Similar would be for RestaurantController and FoodController of course just constructor injecting.
How do I use Ninject in such example? Do I need some global IService and not ITownService, IRestaurantService and IFoodService which I'd inherid in TownService, RestaurantService and FoodService or is it okay like this?
When binding what do I need to bind?
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
kernel.Bind<ITownService>().To<TownService>();
kernel.Bind<IRestaurantService>().To<RestaurantService>();
kernel.Bind<IFoodService>().To<TownService>();
Something like this?
In short - what I need for adding dependency injection with Ninject?
I'm really having problems with this and would need help.
Thanks a lot in forward.
From the package manager console run this command:
Install-package Ninject.MVC3
This will add a class to App_Start/NinjectWebCommon.cs
If you look near the bottom there is a RegisterServices method.
You simply add the code from your question there i.e.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
kernel.Bind<ITownService>().To<TownService>();
kernel.Bind<IRestaurantService>().To<RestaurantService>();
kernel.Bind<IFoodService>().To<TownService>();
}
I'm going to test my EF Models. In order to do this I've create IDbContext class. But I don't know how to rewrite my Save and Delete methods, because I don't know how to write
db.Partner.AddObject(obj); How to rewrite these methods?
public interface IDbContext
{
int SaveChanges();
DbSet<Partner> Partner { get; set; }
}
public class PartnerRepository : IPartnerRepository
{
readonly IDbContext _context;
public PartnerRepository()
{
_context = (IDbContext)new VostokPortalEntities();
}
public PartnerRepository(IDbContext context)
{
_context = context;
}
public void Save(Partner obj)
{
using (var db = new VostokPortalEntities())
{
if (obj.PartnerID == 0)
{
db.Partner.AddObject(obj);
}
else
{
db.Partner.Attach(obj);
db.ObjectStateManager.ChangeObjectState(obj, System.Data.EntityState.Modified);
}
db.SaveChanges();
}
}
public void Delete(Partner obj)
{
using (var db = new VostokPortalEntities())
{
db.Partner.Attach(obj);
db.ObjectStateManager.ChangeObjectState(obj, System.Data.EntityState.Deleted);
db.SaveChanges();
}
}
public List<Partner> GetAll()
{
using (var db = new VostokPortalEntities())
{
return db.Partner.OrderByDescending(i => i.PartnerID).ToList();
}
}
}
Is this proper way to test EF Models?
Unit-testing of repositories takes a lot of time and does not give you many benefits. Why? Because repository don't have complex business logic. Usually there is pretty simple calls to underlying data-access API (i.e. ORM). I think it's match better to spend time on writing full-stack acceptance tests, which also will show if your repository do its job.
BTW there is interesting rule Don't Mock what you don't own:
By testing interactions with a mocked version of type we don't own, we
really are not using our test to check for the correct behavior, nor
to drive out a collaborator’s design. All our test is doing is
reiterating our guess as to how the other type works. Sure, it’s
better than no test, but not necessarily by much.