0

Environment: ASP.NET MVC3 C#

Say I have some repository (semi-psuedo):

public interface IRepository
{
 create();read();update();delete();opendb();closedb();
}

public class CarRepository : IRepository
{
 private DbContext namedDbContext;

 public void opendb()
 {
  namedDbContext = new DbContext();
 }
 public void closedb()
 {
  namedDbContext.dispose();
 }
}

And then in a controller the repository is injected and used as follows to manually control the db connection lifetime:

public class SomeController : Controller
{
    private IRepository CarRepository;

    public void SomeController(IRepository _carRepository)
    {
        CarRepository = _carRepository;
    }

    public ActionResult SomeAction(int CarId)
    {
        CarRepository.opendb();
        var car = CarRepository.read(CarId);
        CarRepository.closedb();
    }
}

Is this considered bad practice because it is taking the control of the connection from the repository and placing it in the controller? I am worried about memory leaks from using dependency injection and want to ensure duplicate connections are not opened, nor long running and unused.

Travis J
  • 81,153
  • 41
  • 202
  • 273
  • And what would be an advantage of such manual control? There are some obvious disadvantages but I could hardly see any advantages. – Wiktor Zychla Feb 13 '12 at 19:32
  • This sounds like fear of the unknown. You should just dive in with an IoC container and have fun. `Install-Package Autofac.Mvc3` – cwharris Feb 13 '12 at 19:36
  • The mvc3 framework uses IDependencyResolver which has no dispose method, and I was thinking of using manual control over at least the connection to ensure there are no memory leaks. – Travis J Feb 13 '12 at 19:37
  • `IDependencyResolver` is just a service locator contract. It's up to each implementor to decide how to clean up resources. – jgauffin Feb 13 '12 at 21:38
  • Looks like this might be a ready fire aim situation :( Guess I will go fill up the bucket and look for holes. – Travis J Feb 13 '12 at 21:42
  • @TravisJ: There are no holes. Use the existing nuget package for Unity. – jgauffin Feb 14 '12 at 08:21
  • @jgauffin - I think I will wait for another iteration from the mvc team, there are holes and memory leaks are a significant concern. If you wish to use service location then that is your prerogative. See the link in my comments below if you want to read up on some of them. No time to discuss all of them here. – Travis J Feb 14 '12 at 19:12
  • @TravisJ: The source code is freely available. I've studied it do be able to make the integrations that I've made. Look at my github account. I would love to hear about the holes that you have found, since I have not found anything major. And I bet that the MVC team would love hear about them too. – jgauffin Feb 14 '12 at 19:17
  • @jgauffin - I have a copy of the source code. The mvc team is doing an awesome, fantastic job with their iterations and does not need input from me. Moreover, DI is not a significant concern of theirs and Brad Wilson points out that only a small population actually uses DI. – Travis J Feb 14 '12 at 19:28
  • I simply do not understand what holes or memory leaks you are talking about? – jgauffin Feb 14 '12 at 19:40

3 Answers3

2

Yes. Sure. Most ADO.NET drivers uses connection pooling, so the actual connection process isn't that heavy. And you have TransactionScope which can take care of transaction over multiple connections, but it wont be as fast as one transaction over one connection.

I am worried about memory leaks from using dependency injection and want to ensure duplicate connections are not opened, nor long running and unused.

A IoC will guaranteed clean up the connection (a large user base have made sure of that). There is no guarantee that a programmer will do the cleanup in all places.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • I am using Unity with a controller factory. So you don't think nested dependencies will become memory leaks by Unity (or by mainstream DI containers in general)? – Travis J Feb 13 '12 at 19:33
  • +1 for "a programmer wont." Haha. Are we human or are we dancers? – cwharris Feb 13 '12 at 19:34
  • @TravisJ: Depends on how you use Unity. You have to do proper cleanup. Install the nuget package `unity.mvc3` or look at it's source code. – jgauffin Feb 13 '12 at 19:34
  • @jgauffin - You mention scopes, is TransactionScope part of the Unity framework? Do you know where I could find a list of them? – Travis J Feb 13 '12 at 19:49
  • To have unity clean it up you need the hierarchicallifetimemanager – Adam Tuliper Feb 13 '12 at 19:57
  • 1
    `TransactionScope` is a new class in .NET 4 and is found in `System.Transactions`. – jgauffin Feb 13 '12 at 20:08
  • For analysis of why transaction scope will still cause memory leaks, see this post on SO: http://stackoverflow.com/questions/5129789/unity-2-0-and-handling-idisposable-types-especially-with-perthreadlifetimemanag – Travis J Feb 13 '12 at 20:39
  • btw for me was difficult to use transactions with EF, because of the requierments of TransactionScope, that's why I'm using Nhibernate or a micro orm. AS for DI, I'm using Autofac which seems to know to call Dispose on disposable objects without any cfg. – MikeSW Feb 13 '12 at 20:51
  • @MikeSW: So does most containers as long as you download a MVC3 integration package like `ninject.mvc3`, `autofac.mvc3` or `unity.mvc3`. – jgauffin Feb 13 '12 at 21:36
  • @TravisJ: transaction scope is NOT causing memory leaks. Improper use of `PerThreadLifetimeManager` will. The `HiearchicalLifetimeManager` are used when working with MVC3. – jgauffin Feb 14 '12 at 19:19
1

Part of a repository is abstracting away the details of persistence.

I see two problems with your proposal:

  1. You are leaking the abstraction more than necessary by naming these methods "opendb" and "closedb" and
  2. If you go down this route, you should return IDisposable (the connection object) from the opendb() method, and wrap the action in a using block to ensure that the connection gets closed.

Typically, you can just let the repository create a connection for each method, so you just have to get it right in your repository methods. The challenge comes when you want to perform multiple actions against the repository, without using a separate connection for each piece.

To achieve that, you could expose the notion of a unit-of-work from the repository. Your unit of work will implement the interface for the repository's methods, so you can't call them outside of a unit-of-work. It will also implement IDisposable, so whenever you call into your repository you will use a using block. Internally, the repository will manage the connection, but will neither expose the connection nor "talk about it."

For example:

public ActionResult SomeAction(int CarId)
{
     using (var repo = CarRepository.BeginUnitOfWork())
     {
        var car = repo.read(CarId);
        // do something meaningful with the car, do more with the repo, etc.
     }
}
Jay
  • 56,361
  • 10
  • 99
  • 123
  • Don't UnitOfWork patterns usually contain the repository as a dependency? – Travis J Feb 13 '12 at 19:48
  • @TravisJ Yeah, this wouldn't be a unit-of-work pattern implementation and is not transactional. I'm struggling for a better name, though. – Jay Feb 13 '12 at 20:03
1

The REpository pattern provides an abstraction of the persistence layer. It shouldn't expose any of the persistence details such as db connection. What if the storage is an xml file, or a cloud storage?

So yes, it is bad practice. If you want more control, you might make the repository use the unit of work pattern, so that a higher level should decide when a transaction is commited, but that's it. No knowledge of the database should be exposed by the repository.

AS for memory leaks, make repository implmement IDIsposable (where you close any outstanding open conenctions)and just makes sure that the DI container manages a repository instance per request, it will call Dispose on it.

MikeSW
  • 16,140
  • 3
  • 39
  • 53
  • My concern is that, sometimes in the mvc3 framework when a shallow copy of a data context object is made it can force the connection to remain active. Is IDisposable more reliable than using(){}? – Travis J Feb 13 '12 at 20:00
  • the using statement requires IDisposable in the first place. Don't be concerned about what EF does, any orm will close the db connection as soon as it can. – MikeSW Feb 13 '12 at 20:18
  • Unfortunately, this does not seem to be the case, especially not with nested dependencies. – Travis J Feb 13 '12 at 20:40
  • you're saying that EF is leaky? I don't use it so I can't vouch for it, but closing the db connection is pretty basic stuff. Worst case scenario, DbContext implements IDisposable which means it will clsoe any open connection when disposed and Jay presented how to properly use the DbContext. – MikeSW Feb 13 '12 at 20:47
  • EF is not leaky per say, although I can make it leak pretty easily. You can see an example of someone encountering this issue on SO: http://stackoverflow.com/questions/8619483/datacontext-accessed-after-dispose-error-when-disposing-datacontext-from-actio/9267097#9267097 . Having dependencies implement IDisposable is a "code smell" (according to mark seemann). Moreover, it is not necessarily EF which will leak as much as a DI container holding the EF as a dependency. For example, if there are two dependencies with the same EF Context, and one is released early, the other will have no context – Travis J Feb 13 '12 at 20:55
  • This is a complex situation, and can require custom code to manage, and sometimes depending on how complex the object graph it can be a lot of code. These situations lead me to wonder if I shouldn't just take back control of the context lifetime. – Travis J Feb 13 '12 at 20:57
  • 1
    When I'm using an orm, usually is Nhibernate and I the flow is tipically like this: i have autofac configured to get me one instance of ISession (equivalent with DbContext) and one instance of repository per request, ISession being injected into repository. Nhibernate closes the db connection as fast as it can, it doesn't wait for ISession to be disposed and autofac calls dispose on ISession and Repository automatically when the request ends. No memory leaks and no dependecy problems there. Continuing -> – MikeSW Feb 13 '12 at 21:29
  • 1
    If you really need to pass DBContext around as a dependency, maybe you should dispose it once when the request ends. – MikeSW Feb 13 '12 at 21:30
  • I would love to dispose of it when the request ends :) That is the whole goal here, it's just that Unity wont always automatically dispose of it which causes memory leaks and lead me to asking this question. – Travis J Feb 13 '12 at 21:39