The Repository Pattern with EF code first & Dependeny Injection in ASP.NET MVC3
Introduction
In these days i started use EF code first and think about how could i take the advantage form it for my recent project. My project is base on MVC3 and there are some challenges to continue update this project. At that time i must finish my job in a very shortly deadline so fast so good i just define some data access interfaces and implemented them with EF4.
There are some things in my project troubling me:
- I have used the EF entities in my controllers anywhere that there is a connection translation error throwing infrequently.
- Modules coupling degree becoming closed.
- Manage services and contexts life cycle are difficult.
Obviously it needs to refactory my project with a new architecture designing.
Preparing
Before start my work i need to do some researching and learning. I have read a large numbers of articles about DDD, SOA,EF code first, Dependency Injection pattern, Repository pattern even watch all web casts about MVC on ASP.NET and a week later ....
I have really found some useful resources about those topics and i sharing them below:
- ASP.NET MVC Storefront Starter Kit videos
- Repository Pattern - by Martin fowler
- Microsoft Unity 2.0
- A dependency injection library for .net
- "ASP.NET MVC 3 Service Location" - by Brad Wilson
Repository Pattern with EF Code first
When i finish my learning on EF code first and Repository i couldn't found any solutions for implement Repository pattern with EF code first. EF4.1 is so powerful for building the DAL that it allows us using POCO objects to define our database and BO(business objects.) instead of inherit from Entity that could be give me a big hand. I could very easy to define the repository interface like below:public interface IRepository<T>: IDisposable where T : class { IQueryable<T> All(); IQueryable<T> Filter(Expression<Func<T, bool>> predicate); IQueryable<T> Filter<Key>(Expression<Func<T, bool>> filter , out int total, int index = 0, int size = 50); bool Contains(Expression<Func<T, bool>> predicate); T Find(params object[] keys); T Find(Expression<Func<T, bool>> predicate); T Create(T t); void Delete(T t); int Delete(Expression<Func<T, bool>> predicate); int Update(T t); int Count { get; } }
Dependency Injection in MVC3
In Mvc3 we could use the DependencyResolver.SetResolver(IDependencyResolver resolver) to register a Dependency Injection Container and use IDependencyResolver.GetService() method to locate our registered service instance that is a very amazing feature in this version. For more about DI in MVC3 you could read the "ASP.NET MVC 3 Service Location" below.Unity
We could found many popular DI framework in google such as Castle Windsor, Structuremap,ObjectBuilder, Managed Extensibility Framework (MEF) and Microsoft Unity, I'd like to use Microsoft Unity 2.0 because the MVC DI features in comes from it that means we could very easy to implement DI in our Mvc applications.
References from MSDN:
Unity is a lightweight, extensible dependency injection container that supports interception, constructor injection, property injection, and method call injection. You can use Unity in a variety of different ways to help decouple the components of your applications, to maximize coherence in components, and to simplify design, implementation, testing, and administration of these applications.
Unity is a general-purpose container for use in any type of Microsoft® .NET Framework-based application. It provides all of the features commonly found in dependency injection mechanisms, including methods to register type mappings and object instances, resolve objects, manage object lifetimes, and inject dependent objects into the parameters of constructors and methods and as the value of properties of objects it resolves.
In addition,
Unity is extensible. You can write container extensions that change the behavior of the container, or add new capabilities. For example, the interception feature provided by Unity, which you can use to add policies to objects, is implemented as a container extension.
Implementation
Now let's go to create a demo to implement the Repository pattern with EF4.1 and DI in our Mvc3 application. There are 2 projects in my Demo solution they are :
- Demo.DAL - Contains IRepository and POCO objects.
- Demo.Web - The Mvc3 web application.
We are already define the IRepository interface above, now we need to implement the IRepository.
using System; using System.Linq; using System.Linq.Expressions; using System.Data.Entity; using System.Collections.Generic; using System.Data; namespace Demo.DAL { public class Repository<TObject> : IRepository<TObject> where TObject : class { protected DB Context; public Repository() { Context = new DB(); Context.Configuration.AutoDetectChangesEnabled = false; } protected DbSet<TObject> DbSet { get { return Context.Set<TObject>(); } } public void Dispose() { if (Context != null) Context.Dispose(); } public virtual IQueryable<TObject> All() { return DbSet.AsNoTracking(); } public virtual IQueryable<TObject> Filter(Expression<Func<TObject, bool>> predicate) { return DbSet.Where(predicate).AsQueryable<TObject>().AsNoTracking<TObject>(); } public virtual IQueryable<TObject> Filter(Expression<Func<TObject, bool>> filter, out int total, int index = 0, int size = 50) { int skipCount = index * size; var _resetSet = filter != null ? DbSet.Where(filter).AsQueryable() : DbSet.AsQueryable(); _resetSet = skipCount == 0 ? _resetSet.Take(size) : _resetSet.Skip(skipCount).Take(size); total = _resetSet.Count(); return _resetSet.AsNoTracking().AsQueryable(); } public bool Contains(Expression<Func<TObject, bool>> predicate) { return DbSet.Count(predicate) > 0; } public virtual TObject Find(params object[] keys) { return DbSet.Find(keys); } public virtual TObject Find(Expression<Func<TObject, bool>> predicate) { return DbSet.FirstOrDefault(predicate); } public virtual TObject Create(TObject TObject) { var newEntry = DbSet.Add(TObject); Context.SaveChanges(); return newEntry; } public virtual int Count { get { return DbSet.Count(); } } public virtual int Delete(TObject TObject) { var entry = Context.Entry(TObject); if (entry.State == EntityState.Detached) DbSet.Attach(TObject); DbSet.Remove(TObject); return Context.SaveChanges(); } public virtual int Update(TObject TObject) { var entry = Context.Entry(TObject); DbSet.Attach(TObject); entry.State = EntityState.Modified; return Context.SaveChanges(); } public virtual int Delete(Expression<Func<TObject, bool>> predicate) { var objects = Filter(predicate); foreach (var obj in objects) DbSet.Remove(obj); return Context.SaveChanges(); } } }
Please notes that i have disable the AutoDetectChangeEnabled for dbContext and return all collection as AsNoTracking() ,AutoDetectChangesEnabled = false . Because the data tracking is an evil for ASP.NET application it will be harm for performance. Now i create the Product and Category objects and DbContext like below:
namespace Demo.DAL { public class Category { [Key] public int ID { get; set; } public string Name { get; set; } public string Title { get; set; } } public class Product { [Key] public int ID { get; set; } public int CategoryID { get; set; } [ForeignKey("CategoryID")] public virtual Category Category {get;set;} public string Name { get; set; } public string Title { get; set; } public string Description{get;set;} public decimal Price { get; set; } } public class DB : DbContext { public DB() : base("DemoDB") { } public DbSet<Category> Categories; public DbSet<Product> Products; } }
The DAL has been done! Constantly we need to create the SL (Service Layer) but now in this demo i just have one service : ICatalogService
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.Practices.Unity; using Demo.DAL; namespace Demo.Services { public interface ICatalogService { List<Category> GetCategories(); List<Product> GetProducts(); Product AddProduct(Product product); } public class CatalogService:ICatalogService { [Dependency] public IRepository<Category> Categories { get; set; } [Dependency] public IRepository<Product> Products { get; set; } public List<Category> GetCategories() { return Categories.All().ToList(); } public List<Product> GetProducts() { return Products.All().ToList(); } public Product AddProduct(Product product) { return Products.Create(product); } } }
The next step is create a DependencyResolver for MVC :
namespace Demo.Web { public class UnityDependencyResolver : IDependencyResolver { readonly IUnityContainer _container; public UnityDependencyResolver(IUnityContainer container) { this._container = container; } public object GetService(Type serviceType) { try { return _container.Resolve(serviceType); } catch { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return _container.ResolveAll(serviceType); } catch { return new List<object>(); } } } }
Open the Global.asax and register types and set DependencyReslover in Application_Start
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); var container = new UnityContainer(); container.RegisterType<ICatalogService, CatalogService>(new PerThreadLifetimeManager()) .RegisterType<IRepository<Category>, Repository<Category>>() .RegisterType<IRepository<Product>, Repository<Product>>(); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); }
Finally we could inject the ICatalogService in HomeController now.
public class HomeController : Controller { private ICatalogService service; [Dependency] public ICatalogService Service { get { return service; } set { service = value; } } public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewData.Model = Service.GetProducts(); return View(); } public ActionResult About() { return View(); } }
That's all enjoy!
Post Comment
wuhSL0 This very blog is without a doubt interesting and besides diverting. I have picked up helluva useful stuff out of this amazing blog. I ad love to go back every once in a while. Thanks!
TpHwdj Your idea is outstanding; the issue is something that not enough persons are speaking intelligently about. I am very happy that I stumbled throughout this in my seek for one thing regarding this.
5atdug wow, awesome blog article.Thanks Again. Really Cool.
F0WKN1 Thanks so much for the blog post.Much thanks again. Really Cool.
GqM0H2 It as the little changes that make the biggest changes. Many thanks for sharing!
Tofq8D There is visibly a lot to realize about this. I think you made certain good points in features also.
HlpgyE You created some decent points there. I looked on the internet for the problem and located most individuals will go along with along with your internet site.
L9Hoik Major thanks for the post.Really looking forward to read more. Will read on
VRMXux Very informative article.Really looking forward to read more. Keep writing.
Thanks for great article! I like it very much!
wPZ9RN Thanks for the blog post.Thanks Again. Want more.
uYhmEr Thanks again for the blog.Much thanks again.
EjV6zn
2Mj8MF thanks for sharing source files. many thanks
DDm7m2 Very useful information specifically the last part I care for such information a lot. I was looking for this certain information for a very long time. Thank you and good luck.
Vx3ys5 Thanks-a-mundo for the blog article.Really looking forward to read more. Want more.
I6cs6u What i discover troublesome is to find a weblog that may capture me for a minute however your blog is different. Bravo.
RqwxXU Very good post.Much thanks again. Cool.
EBgM2A fantastic issues altogether, you just won a new reader. What may you suggest in regards to your put up that you made some days ago? Any sure?
vRVFJP It's onerous to find educated folks on this subject, however you sound like you already know what you're talking about! Thanks
fCKHRU excellent post, very informative. I wonder why the opposite specialists of this sector don't understand this. You should proceed your writing. I am confident, you have a great readers' base already!
s4MJ5l Greetings! I've been reading your web site for a long time now and finally got the courage to go ahead and give you a shout out from Dallas Texas! Just wanted to mention keep up the great job!
SKAwUg I'm still learning from you, as I'm improving myself. I certainly love reading everything that is written on your website.Keep the tips coming. I loved it!
W2ua5p Im thankful for the article post.Thanks Again. Awesome.
yk7oRn Wow, superb blog layout! How lengthy have you been running a blog for? you made running a blog glance easy. The total look of your web site is magnificent, let alone the content material!
dDyB9v You made some clear points there. I did a search on the subject matter and found most people will approve with your site.
TbES79 I really enjoy the article.Much thanks again. Cool.
gZr5U6 Appreciate you sharing, great article.Really thank you! Really Great.
5KX3qO I really enjoy the article.Thanks Again. Will read on...
w0VtJ2 Really informative blog post.Really thank you! Cool.
X4EA2d I really enjoy the blog article.Much thanks again. Will read on...
sfWge7 A big thank you for your blog. Awesome.
g6f2pt I really liked your article.Much thanks again. Really Cool.
jhh55y Muchos Gracias for your blog article.Really thank you! Will read on...
WJaiqw Looking forward to reading more. Great blog.Thanks Again. Keep writing.
8I6u1b Im thankful for the blog post. Really Cool.
Bu77WL I think this is a real great blog.Really looking forward to read more. Keep writing.
Fc9FmD Major thanks for the post.Really looking forward to read more. Really Great.
fIEqa1 Im obliged for the blog article. Keep writing.
I love to read you site
betting.pwYF2Onu Really appreciate you sharing this article post.Really looking forward to read more. Awesome.
ci84iS wow, awesome article.Really thank you! Will read on...
oXIckB Thank you for your article post. Much obliged.
RDCwOo Really appreciate you sharing this blog article.Much thanks again. Much obliged.
S2rSKU Thank you ever so for you article post.Really thank you! Really Cool.
jQYly3 I loved your article post.Really looking forward to read more. Awesome.
GuSz0a Enjoyed every bit of your blog post.Really looking forward to read more. Cool.
eLEm7h Thanks-a-mundo for the article.Thanks Again. Want more.
m2onlW Major thanks for the post.Much thanks again. Will read on...
eJRJfs A round of applause for your post.Thanks Again. Cool.