Using Dependency Injection
As others have said and will probably reiterate, the 'right way' is often considered to be dependency injection.
In my latest project, I've organized things so that I'm almost done with the project and DI has been so effortless that I'm doing it myself (rather than using an injector). One major factor in that has been adhering fairly strictly to this structure:
WebProject
| |
| DataServices
| | |
ViewModels EntityModels
Access to all data services during one unit of work occurs through a single DataServiceFactory instance, that requires an instance of MyDbContext. Another factor has been an entirely RESTful application design - it means I don't have to intersperse persistence functionality throughout my code.
Without Dependency Injection
That said, maybe DI isn't right for you on this project. Maybe:
- you don't plan to write unit tests
- you need more time to understand DI
- your project structure already has EF deeply integrated
In ASP.NET MVC, the unit of work often entirely coincides with the request lifetime - i.e. HttpContext.Current
. As a result, you can lazily instanciate a repository 'singleton' per-request, instead of using DI. Here is a classic singleton pattern with current context as the backing store, to hold your DbContext
:
public class RepositoryProxy {
private static HttpContext Ctx { get { return HttpContext.Current; } }
private static Guid repoGuid = typeof(MyDbContext).GUID;
public static MyDbContext Context {
get {
MyDbContext repo = Ctx.Items[repoGuid];
if (repo == null) {
repo = new MyDbContext();
Ctx.Items[repoGuid] = result;
}
return repo;
}
}
public static void SaveIfContext() {
MyDbContext repo = Ctx.Items[repoGuid];
if (repo != null) repo.SaveChanges();
}
}
You can SaveChanges
automatically too, if you are feeling especially lazy (you'll still need to call it manually to inspect side-effects, of course, like retrieving the id for a new item):
public abstract class ExtendedController : Controller {
protected MyDbContext Context {
get { return RepositoryProxy.Context; }
}
protected override void OnActionExecuted(ActionExecutedContext filterContext) {
RepositoryProxy.SaveIfContext();
base.OnActionExecuted(filterContext);
}
}