14

First, let's see what Microsoft says about Asp.Net Core's default Dependency Injection services:

The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#disposal-of-services

I.e. the framework would be calling a classes Dispose method (assuming the class implements IDisposable)

Second, the DbContext class does indeed implement IDisposable out of the box.

Third, in our Startup.cs class, we add our DbContext via the AddDbContext method, which by default gets added as a Scoped instance (i.e. our DbContext is created and garbage collected on each single request).

Scoped lifetime services are created once per request.

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#service-lifetimes

E.g.

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddDbContext<TheStoreDbContext>(ConfigureDbContext)      
        .AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) 
}

Conclusion, we don't need to explicitly call context.Dispose() anywhere in our Asp.net Core application.

So why are there so many examples online and in tutorials which show you that you have to implement IDisposable in your Repository or UnitOfWork classes?

E.g.

public class UnitOfWork : IUnitOfWork
    {
        private readonly DbContext _context;

        public IProductRepository ProductRepository { get; }

        public UnitOfWork(DbContext context)
        {
            _context = context;
            ProductRepository = new ProductRepository(context);
        }

        public void Dispose()
        {
            _context.Dispose();
        }
    }

What do you think? Is this a valid question? Does it make sense not to explicitly call the Dispose() method anywhere?

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
Francisco Vilches
  • 3,426
  • 1
  • 15
  • 18
  • 3
    Do you **have** to? No, I don't for the same reason - I leave the framework clean up, but then again the applications I use ASP.NET Core in are not performance or memory critical. If you have a lot more going on then it is good to implement `IDisposable` to deconstruct your resources. Is leaving cleanup for the framework good practice, would that fly by in C++? Not really, you'd run into problems over time. – ColinM Jan 29 '19 at 09:24
  • 2
    If you using DI, typically you'd let the DI framework dispose of your object for you. You need to set to the correct lifestyle to prevent memory leaks, so I always avoid this. Any non injected dependencies though should be cleaned up yourself. The `Dispose` call is still important, it just depends who calls it, you or the DI framework. – Liam Jan 29 '19 at 09:26
  • *we don't need to explicitly call context.Dispose() anywhere in our Asp.net Core application* no. Don't do this. There is no "you don't **ever** have to do this". It depends. – Liam Jan 29 '19 at 09:28
  • 2
    Possible duplicate of [How to dispose resources with dependency injection](https://stackoverflow.com/questions/4483659/how-to-dispose-resources-with-dependency-injection) – Liam Jan 29 '19 at 09:31
  • @Liam good point. I can picture solutions that would have a project or library solely for data access. This project might be used by your Asp.net Core presentation project as well as, say, a Console app for e.g. In this case, yes, I agree it would be a good idea to make your relevant classes (e.g. UnitOfWork) implement IDisposable, so it gives other calling methods/projects/etc. the options to dispose manually. – Francisco Vilches Jan 29 '19 at 09:34
  • 2
    the Tl;Dr is if a dependency implements `IDisposable` you should always call `Dispose`. How you do that is up to you. – Liam Jan 29 '19 at 09:36
  • 2
    Although I am sure (as hinted by ColinM's coment) that there are indeed performance-critical cases where you'd want to manually Dispose a DbContext instance, the "reason" why people do it is often because it's just blindly copied from someone else Cargo-Cult Style :) Also, as regards the UoW/Repository example - DbContext is *already* providing that (the context is a Unit of Work and DBSet is a Repository) so any examples you see like the one you have in the question may not necessarily represent best practice :) – Stephen Byrne Jan 29 '19 at 14:08
  • This is the best question I have seen. But unfortunately I didn't see any pointed answer for this question, and I also have no idea, do we really need to implement the IDispose. But again salute for this question, it was asked with all points. – Harshan Mar 19 '22 at 13:14

1 Answers1

19

The rule of thumb is that a class should only dispose what it owns. In the case of the UnitOfWork, however, it does not own the DbContext, as it is not created by UnitOfWork—instead it provided from the outside by someone else.

Letting UnitOfWork dispose of that DbContext can even be problematic, because UnitOfWork has no way of knowing whether or not DbContext is still used by other classes in the system when UnitOfWork is disposed of. In other words, the application might break when UnitOfWork starts disposing that dependency.

So if you follow the rule of only disposing what you own, it means that UnitOfWork should in fact not implement IDisposable at all. And this means that you let 'someone else' control the lifetime of the DbContext.

This idea of moving the control over the lifetime of dependencies (such as DbContext) to a third party is not something new, and certainly not something specific to the new Microsoft DI container. This is in fact an old idea, which is the idea that you centralize the control over the lifetime of application components in the start-up path of the application. In the context of DI, this start-up path is typically referred to as the Composition Root.

Inside the Composition Root, it will be the job of the Composer to create application components, manage their lifetime, and dispose of them when they are not needed any longer. A DI Container (like the .NET Core DI Container) acts as the Composer in your system, but you can do this just as well by hand—a practice commonly known as Pure DI.

Also see this answer, which also talks about disposing in the context of the SOLID principles.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • this is not a bad practice because how do you know you have to dispose of your dependencies or not? the dependency injection is bad practice because the best practice is every class must dispense its dependencies, but in dependency injection, if you don't do that you will get memory overflow because in IO operations like DB contexts someone must call the disposable, the question is who? – Ali Yousefi Sep 14 '21 at 04:38
  • the example is working on streams, if you call dispose method of the main class that will dispose of child stream too. that is not like the unit of work example. MemoryStream memoryStream = new MemoryStream(); var writer = new StreamWriter(memoryStream); writer.Dispose(); //exception throw memoryStream.WriteByte(1); – Ali Yousefi Sep 14 '21 at 04:44