1

I know the using keyword basically calls Dispose() after scope ends, however, is it bad practice or unacceptable to have the variable from the using clause be a class field? Example:

public class ValuesController : ApiController
{
        DatabaseEntities db;

        public ValuesController()
        {
            db = new DatabaseEntities();
        }

        public IHttpActionResult GetList()
        {
            return Ok(db.Values.ToList());
        }
}

vs:

public class ValuesController : ApiController
{     
        public IHttpActionResult GetList()
        {
            using (DatabaseEntities db = new DatabaseEntities())
            {
                 return Ok(db.Values.ToList());
            }
        }
}

Will the DatabaseEntities properly dispose after the API call is complete in the first example? Is the first example bad practice?

Chad K
  • 832
  • 1
  • 8
  • 19

3 Answers3

4

It is safe to encapsulate it in your Controller, but only if you Dispose it in the Controller's Dispose(bool). eg:

public class ValuesController : ApiController
{
    DatabaseEntities db;

    public ValuesController()
    {
        db = new DatabaseEntities();
    }

    public IHttpActionResult GetList()
    {
        return Ok(db.Values.ToList());
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
}

But using DI is easier than overriding Dispose(bool) on your controllers, so it's probably not a best-practice.

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
  • Will the DI container call `Dispose()` on the `DatabaseEntities` object? – Robert Harvey Nov 19 '19 at 22:55
  • If it's any good it will:) eg: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0#scoped – David Browne - Microsoft Nov 19 '19 at 22:58
  • 1
    This looks like the best solution for my use case. I don't want to dependency inject because that would require changing code that's already working and not really mine to change – Chad K Nov 20 '19 at 15:07
3

The first example is bad practice on two counts

  1. You should inject your dependencies into the controller using a DI library

  2. If your DatabaseEntities class uses non-managed resources (like say some COM objects built on Win32, etc) then it will not be disposed of by the GC properly; the class itself might have a finaliser method it calls when it goes out of scope but in general it's not a good idea to rely on these being present. The net effect of this can be both memory leaks and loss of service in some cases (like if the underlying COM server has a limited pool of objects, or if a finaliser crashes, etc).

There's a great discussion about that here

And, even if it is is a fully managed class, it will not be disposed of until the next GC cycle in your scenario, net result being performance issues.

So your code should look like this (note, here I'm using an interface which is also considered good practice in terms of abstracting the actual implementation of the dependency).

public class ValuesController : ApiController
{
        readonly IDatabaseEntities _db;

        //here db is being provided to the ctor by your
        //DI Library e.g. StructureMap, SimpleInjector, .Net Core Injection, etc.
        public ValuesController(IDatabaseEntities db)
        {
            _db = db; //null check left out for brevity
        }

        public IHttpActionResult GetList()
        {
            return Ok(_db.Values.ToList());
        }
}

The beauty of this is that your DI container is now responsible for disposing of your DatabaseEntities instances, and not you. And it makes your ValuesController easier to test in isolation as well.

Stephen Byrne
  • 7,400
  • 1
  • 31
  • 51
  • Still doesn't dispose. – Robert Harvey Nov 19 '19 at 22:49
  • @RobertHarvey: The idea is that it's no longer this class's responsibility to dispose. – StriplingWarrior Nov 19 '19 at 22:51
  • @StriplingWarrior: Well, sure, but if you're not going to address the object's lifecycle, it just begs the question anyway. – Robert Harvey Nov 19 '19 at 22:51
  • @RobertHarvey - could well be that I'm wrong, but I was always under the impression that most libraries will dispose (assuming the dependency implements `IDisposable`) when the object goes out of scope according to whether it's Transient, Scoped, etc. But happy to learn if that's not the case! – Stephen Byrne Nov 19 '19 at 23:00
  • Shouldn't your constructor parameter be an interface, and not a concrete type? – Robert Harvey Nov 19 '19 at 23:03
  • True, but was trying to keep it as simple as possible, I'll update it anyway as it's probably more idiomatic to inject the abstraction :) – Stephen Byrne Nov 19 '19 at 23:06
  • @StephenByrne whether the DI container disposes or not depends on how the service/context was registered. In .NET Core, only scoped services get disposed. In *ASP*.NET Core, transient services used by a controller are treated as scoped too. – Panagiotis Kanavos Nov 20 '19 at 17:42
  • @PanagiotisKanavos - sure, that makes sense – Stephen Byrne Nov 20 '19 at 21:07
0

I have 2 rules about Disposeables that have never failed me:

  1. Never split up the creation and disposing. Create, Use, Dispose. All in teh same piece of code, ideally using a using block.
  2. There are cases when you can not follow Rule 1. Mostly because your class contains something Disposeable, that needs to be kept open. In that case you implement IDisposeable for the sole purpose of relaying the dispose call. Indeed that is about the reason 95% of all classes do implement IDisposeable - because they may have to do that kind of relay.

In case 2 whoever uses your class follows rule 1.

Making a class field of something Disposeable except a case 2, will really only risk stuff like "trying to work with it when already disposed" and "trying to do stuff with it, when nobody should be doing stuff with it". It will just cause issues.

Edit:

Based on your comments, you are mostly worried about the polling application side. If you do polling, there is a very common pattern to have teh whole polling work - loop and all - run in an alternative task or thread. This is my rate-limit code for multithreading, modified with a using:

integer interval = 20;
DateTime dueTime = DateTime.Now.AddMillisconds(interval);

using(someThingDisposeable){
  while(true){
    if(DateTime.Now >= dueTime){
      //insert your work with someThingDisposeable here

      //Update next dueTime
      dueTime = DateTime.Now.AddMillisconds(interval);
    }
    else{
      //Just yield to not tax out the CPU
      Thread.Sleep(1);
    }
  }
}

Modifying it for other forms of Multitasking, only requires using their equivalent for Thread.Sleep.

This code will keep the connection open as long as everything goes well. It will not query the datasource more often then you tell it too. It will never stack up operations. But it will still reliably close the connection on Exceptions. Do not forget to expose the Exception - with Multitasking it is notoriously easy to forget that part. It is a full case 1, minus needing to re-create the connection over and over.

Christopher
  • 9,634
  • 2
  • 17
  • 31
  • All good advice, though I don't think it has much to do with the OP's question. – Robert Harvey Nov 19 '19 at 22:38
  • @RobertHarvey How so? The first example, is a Rule 2. The 2nd example, is a Rule 1. – Christopher Nov 19 '19 at 22:43
  • The reason I don't like using the 'using' keyword is that I have functions that also use the database. I don't want to keep using more 'using'-s because that would create another instance of the database, and if I pass it in, it feels more messy. plus, it adds another indentation that can get quite annoying. Maybe instead, it's a better idea to use the API controller's Dispose method to properly call dispose? – Chad K Nov 19 '19 at 22:49
  • @ChadK: If `DatabaseEntities` works the way it is supposed to (i.e. it's simply an ordinary class instance creation), it should be *very lightweight* anyway. – Robert Harvey Nov 19 '19 at 22:50
  • In my case, it's an entity framework DbContext class – Chad K Nov 19 '19 at 22:53
  • @ChadK: Yep. Very lightweight. The only reason you might not want to create it and dispose it for every request is if you return an `IQueryable` from a method (something you're not likely to do). – Robert Harvey Nov 19 '19 at 22:56
  • I want to do it every request, I just don't want to open up tons of DB connections. This server is polled by a bunch of UIs, so it gets pretty bogged down at times. I want 1 instance per API request. Would David Browne's answer work well? Thanks for all of the advice – Chad K Nov 19 '19 at 22:58
  • @ChadK: Connections are pooled on a SQL Server. If a connection is closed, the server will maintain the connection internally for awhile so that it can be reused. – Robert Harvey Nov 19 '19 at 23:04
  • @ChadK - if you want a single context per request then you can use a DI library and tell it to inject the context as "scoped". Within ASP.Net that will mean one single instance of the context per individual HTTP request (so even if your controller calls a method on another class, and that class also has an injected context, it will be the same context as was in the controller). Not only is this more efficient, but if your database operations are spread out over multiple classes, it's more or less the *only* correct way to do it with DbContext – Stephen Byrne Nov 19 '19 at 23:05
  • @ChadK Never be worried about the performance impact of Dispose. If you do not dispose, you will run into resource starvation. And if your programm fails to resource starvation, all speed is irrelevant. The more modern DB Conneciton classes also have some connection pooling built in. Sp the speed penalty is moderate. – Christopher Nov 19 '19 at 23:07
  • @ChadK: As speed came up, you should read the speed rant. You can skip part 1: https://ericlippert.com/2012/12/17/performance-rant/ | "This server is polled by a bunch of UIs, so it gets pretty bogged down at times." Then your issues is not that it is polled by a **bunch** of UI's. But that it is **polled** by a bunch of UI's. Polling is one of hte most reliable ways to overload any server. – Christopher Nov 19 '19 at 23:10
  • Good point re. the speed issues...and I just want to finally point out that if you are using a scope-injected context, you are *saving* resources and speed, because the connection will only be opened once per request, not per context usage (which is the point, so that the context stays in-synch across classes) – Stephen Byrne Nov 19 '19 at 23:13
  • @ChadK: If polling actually become an issue (again: Speed Rant), stuff like Distributed Databases and push notifications can lessen the load drastically. As would be picking a sensible polling intervall. Fun fact: Most free versions of Virus Scanners can not be set to check for updates more often then every ~2 or so hours. This is most *definitely* in place to limit the server load of those "freeloaders". If it was just the Progreamm writers, no minimum Intervall would be in place anywhere. – Christopher Nov 19 '19 at 23:13
  • @Christopher I appreciate the suggestion. This is for an internal application. Polling is done by a few screens every 3-5 seconds or so. This is all on local network. We tried sockets but they weren't reliable enough and more difficult to set up because we would've had to push the information out, which requires the source of that info to notify or create an event. In our setup, it's just not that feasible – Chad K Nov 20 '19 at 15:00
  • @ChadK A few screens every 3-5 seconds over a local network should not be a noticeable load. I am not even sure why you mentioned it? | Even if it had to create the connection from scratch every time (wich is unlikely), the connection is miniscule work. | If there is anything that slows down DB operations, it is people retreiving too much: A lot of people retreive way more then they display, to do filtering or pagination on the client - never do that! Keep as much filtering work as you can in the Query. – Christopher Nov 20 '19 at 15:37
  • @ChadK: If you do have a programm that is polling a lot, it is not that uncommon to put the whole polling work - using directive and a loop running inside it - into a sperate task or Thread. That way you can keep the connection open, but still have the security that it will be disposed of any exceptions crop up. And with Connections, Exceptions tend to be the exogenous kind. – Christopher Nov 20 '19 at 15:39
  • @ChadK: I added some code for the Polling case to the answer. – Christopher Nov 20 '19 at 15:47