5

Recently I started digging into the concept of Repository Patterns and UnitOfWork together with exploring the EntityFramework.

Made my own implementation based on an MVC example, where they were disposing the UnitOfWork from the Controller like so:

protected override void Dispose(bool disposing)
{
    unitOfWork.Dispose(); 
    base.Dispose(disposing);
}

I'm not into MVC at all, and pretty new in Webforms as well, but I assume they are overriding the Controller dispose method in order to dispose the UnitOfWork as "everything" else is disposed.

Basically I'd like to implement the same concept in my ASP.NET WebForms website and dispose the UnitOfWork that is used behind a Page's code together with the disposing of the Page itself.

I considered adding the same to the Page_Unload event from the life cycle, but I wasn't sure if this is the proper way to do it as I haven't messed with such things before. My idea as follows:

protected void Page_Unload(object sender, EventArgs e)
{
    unitOfWork.Dispose();
    base.Dispose();
}

How can I achieve that safely, and am I on the right track?

  • Possible duplicate of: http://stackoverflow.com/questions/2750111/when-to-call-dispose-in-entity-framework http://stackoverflow.com/questions/4295975/repository-pattern-in-entity-framework-4-when-should-we-dispose http://stackoverflow.com/questions/10777630/questions-about-entity-framework-context-lifetime http://stackoverflow.com/questions/1698628/entity-framework-and-object-context-lifetime-in-asp-net-mvc – Danny Varod Jun 27 '12 at 15:41
  • Thank you for pointing those out, they'd probably be helpful to someone with deeper knowledge who just needs a bit of information to implement what he wants. Not me unfortunately. –  Jun 28 '12 at 17:41
  • Actually, they were so you and others can check if the question is the same as those and if so close this question. Do none of the answers to any of the questions help you? – Danny Varod Jun 28 '12 at 20:01
  • The first one might be helpful, I'll dig into it tomorrow. Certainly not a duplicate though. Afshin's answer got me on the right track, I just need to dig a bit more. Unfortunately I started to see opposite opinions, and considering how fresh I am in the field, I'm afraid of choosing the wrong direction. –  Jun 28 '12 at 20:28
  • In that case, I'll add my answer tomorrow. – Danny Varod Jun 28 '12 at 23:56

2 Answers2

3

First of all: Don't invent the wheel.

Use Dependency Injection frameworks like: StructureMap, Ninject, Unity, etc....

Your UoW should be started with beginning of a web request and disposed when the request is ended.

In other words: DataContext of EF should be initialized when a request is started. Then you can store it somewhere(Session, ...), and it can be reused for that request. One instance of DataContext per request.

But if you try to do it yourself, you are in the wrong way, using a dependency injection framework, would make it so easy.

The framework can handle lifetime of your DataContext(UoW).

Afshin Gh
  • 7,918
  • 2
  • 26
  • 43
  • Thank you for the answer, I'm digging into Dependency Injection frameworks which are a complete stranger to me at the moment. I'll leave this open a bit more until I'm done researching, maybe someone has something to add. –  Jun 28 '12 at 20:30
  • Sure. Because I really like these subjects, I would like to hear from others about these matters. – Afshin Gh Jun 29 '12 at 11:49
  • Okay, I started with Initializing the UnitOfWork myself. I noticed that the BeginRequest event fires for all static files as well which causes repetitive and unneeded initialization of the UoW. Would a DI Framework solve this issue for me (Webforms)? And what would another workaround be? –  Jun 29 '12 at 14:09
  • Take a look at open source applications and how they are doing this: http://kigg.codeplex.com/ or http://orchard.codeplex.com/ or other open source projects. – Afshin Gh Jun 29 '12 at 19:28
  • 1
    I ended up doing it manually but with the idea you provided, and I'm very thankful that you gave me direction. Realized that digging into DI right now will slow me down. I initialized the UnitOfWork in BeginRequest, storing it in the Http.Context.Items. I call it from there where I need it in my code and in the EndRequest I commit any changes and dipose it. Ran some tests with several hundred requests to my page and the database per second, it seems stable. I was afraid of messing something with the disposing, but seems it's "okay" - as okay as it can be for my Junior level. –  Jul 02 '12 at 14:03
  • 1
    You are welcome @Peter. Disposing DataContext in EndRequest is OK but you should commit your changes when it is needed. It's not a good idea to commit what ever changes happened in EndRequest. Commit your changes when you need it, but keep the DataContext alive as long as Request is alive. – Afshin Gh Jul 02 '12 at 16:39
  • Well I assume can safely commit any changes when I need as well, in the middle of my business logic, if needed, but not dispose it of course. I also hooked a Dispose on the Application Error event, but without a commit, in case anything crash and I don't want the data saved. Not sure if that was the right thing to do though. –  Jul 02 '12 at 23:36
  • @Null Beware the technical debt. you say "slow me down" now, I say you'll make that debt back and then some in the future from the time saved when you come to modify/refactor. – Simon Halsey Jul 15 '14 at 01:03
  • @SimonHalsey Technically yes, it's been a while since that question and I know what you mean, but at that point I was working alone and chasing deadlines. The negative side of small software companies. –  Jul 16 '14 at 22:02
1

You should divide your software into layers and components...

UI --> Controller --> Service --> DAL

E.g.

UI.Submit --> Controller.SaveUserInfo --> UsersManagementService.SaveUserInfo -->

public void SaveUserInfo(User user)
{
    using (var uow = new Uow())
    {
        var dbUser = uow.Users.GetByKey(user.Id);
        if (dbUser == null)
        {
            // TODO:
        }

        dbUser.Name = user.Name;
        dbUser.Address = user.Address;
        // Or use a framework for injecting properties

        uow.SaveAndAcceptChanges();
    }
}

You can even receive query logic in certiain service methods e.g.

public User GetUsersMatching(Func<IQueryable<User>, IQueryable<User>> query)
{
    using (var uow = new Uow())
    {
        var users = query(uow.Users).ToList();
        return users;

        // For this to work using POCOs you may need to disable proxy creation
    }
}

However, this makes testing more complex and requires consumers of service to understand the limitations and best practices of LINQ to Entities.

I also recommend not using the pure academic repository-per-base-type pattern, as often to efficiently consume different types of data from the same domain require cross "repository" queries and require join clauses in your LINQ or that the result of multiple queries is combined together and reshaped prior to returning it as one clean result.

Instead treat your services as domain-speicifc-repositories where you can get various types of output. Or in other words, use SOA under your MVC and above your EF.

Danny Varod
  • 17,324
  • 5
  • 69
  • 111