1

I have a ASP.NET Core 6 Web API with this disposable service class:

public interface IMyService: IDisposable { }

public class MyService: IMyService
{
    public void Dispose() => Console.WriteLine("Disposing..."); // never called
}

In program.cs I have this service injected as a singleton:

builder.Services.AddSingleton<IMyService, MyService>();

According to all docs that I could find, the app should call MyService.Dispose() when it shuts down. However this doesn't happen.

What am I missing?

Steps to reproduce:

  1. Create a ASP.NET Core WebAPI project using default template (VS2022)
  2. At the end of program.cs add this code:
     public interface IMyService : IDisposable { }
    
     public class MyService : IMyService
     {
    
         public MyService()
         {
         }
    
         public void Dispose() => Console.WriteLine("Disposing..."); // never called
     }
    
  3. Put a breakpoint on constructor and one on Dispose
  4. Add this line somewhere at the top (after builder is created):
     // Add services to the container.
    
     builder.Services.AddSingleton<IMyService, MyService>();
    
  5. In WeatherForecastController.cs change the constructor signature like this:
     public WeatherForecastController(
         ILogger<WeatherForecastController> logger, IMyService myService)
    
  6. Run the app. In the browser click Get then Try it out then Execute
  7. The break point in MyService constructor shd be hit
  8. Close the browser. The Dispose breakpoint is not hit, Output message is not displayed
Steven
  • 166,672
  • 24
  • 332
  • 435
user628661
  • 81
  • 1
  • 1
  • 9
  • How are you testing this? Stopping the application using the Visual Studio debugger is not the same as stopping the real application. – Steven Nov 23 '22 at 13:30
  • Not related to the question, but consider putting `IDisposable` [solely on the implementation](https://stackoverflow.com/a/30287923/264697) - not the interface. – Steven Nov 23 '22 at 13:40
  • @Steven: I'm using the app to test, I'm not using the debugger to stop it. Also I tried putting IDisposable on implementation but same result – user628661 Nov 23 '22 at 13:56
  • As I said, placing IDisposable on the implementation is unrelated to the question; it won't have any effect. But it might be worth while understanding why placing `IDisposable` on the implementation might actually be better. – Steven Nov 23 '22 at 14:34

3 Answers3

1

It looks like the problem was actually not closing the web app gracefully.If anyone is interested, here is how to gracefully shut down a web app:

user628661
  • 81
  • 1
  • 1
  • 9
  • A small comment: according to the source code, automatic dispose is called from HostingAbstractionsHostExtensions by this invocation: asyncDisposable.DisposeAsync. In my case, the issue was that I adjusted the default `app.Run()` provided by the template and had to manually call the DisposeAsync() method of the main app in order to trigger dispose of underlying services. – Yury Kozlov Jul 27 '23 at 19:31
0

How do you call this service in your project?

In general, you can use the using keyword to call this service:

using (MyService service = new MyService())
{
     service.xxxxxx();
}

In this way, The project will call Dispose() automatically when it shuts down.

But from your question, You are using

 AddSingleton<IMyService, MyService>() 

to register this server. So Dispose() method will only be called when the entire program is shut down. You can change AddSingleton to AddScoped, Then every time you send a new http reqest, you will find Dispose() method be called automatically.

(When using AddSingleton to register service, Only I shut down the project, The Dispose() method can be called automatically)enter image description here

Xinran Shen
  • 8,416
  • 2
  • 3
  • 12
  • According to this doc https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines: The container is responsible for cleanup of types it creates, and calls Dispose on IDisposable instances. Services resolved from the container should never be disposed by the developer. If a type or factory is registered as a singleton, the container disposes the singleton automatically. – user628661 Nov 23 '22 at 12:03
  • 2
    I down voted this answer because I feel that there are multiple incorrect statements in it. 1. In general, classes that are created and managed by the DI Container, should not created nor disposed manually, as shown in the first code example. 2. The DI container will ensure that disposable singletons are disposed off when the container itself gets disposed, which means the statement "you need to call Dispose() method manually when it shuts down" is incorrect. – Steven Nov 23 '22 at 13:34
  • @ Steven, I am very sorry, I misunderstand he is using AddSingleton(new xxxx); instead of builder.Services.AddSingleton(); I have changed my answer, Sorry for providing a wrong answer – Xinran Shen Nov 23 '22 at 13:50
0

TLDR; When running the application as a web service (using IIS), it is the web server that decides whether the web application should be shut down. Closing a web browser will have no effect (unless you are running your application as a developer using the debugger).

Here is a minimal Console application that uses Microsoft.Extensions.DependencyInjection and demonstrates how Singleton services are disposed of when the container itself gets disposed of.

using System;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();

services.AddSingleton<IMyService, MyService>();

using (var container = services.BuildServiceProvider())
{
    container.GetRequiredService<IMyService>();
}

public interface IMyService : IDisposable { }

public class MyService : IMyService
{
    public void Dispose() => Console.WriteLine("Disposing...");
}

When running, this program gives the following output:

Disposing...

You can run this program yourself using .NET Fiddle: https://dotnetfiddle.net/S9gXA8.

Since ASP.NET Core disposed of the container when the application stops, you should see similar behavior. If this is not the case, this could have multiple causes, such as:

  • You are aggressively stopping the application, for instance by stopping the debugger.
  • The type MyService hasn't been created by the container before the application ends. Note that components are created lazily, even Singletons.
  • The application or window closes before you have the time to view the output.
  • The application is actually still running. When running the application as a web service (using IIS), it is the web server that decides whether the web application should be shut down. Closing a web browser will have no effect (unless you are running your application as a developer using the debugger).
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks but none of these causes apply to me. I edited my post and added some steps to reproduce the problem. Maybe you can try it or tell me what am I doing wrong – user628661 Nov 23 '22 at 19:33
  • 1
    Note that closing a web browser does *not* stop a web application. A web application will continue to run until the web *server* decides to stop your web application. Also note that you are stating that your application hits break points. This indicates that the application is in fact running through the (Visual Studio) debugger. This debugger aggressively kills your application without proper shutdown. – Steven Nov 24 '22 at 08:18
  • That's right, thanks. I wrongly assumed that closing the browser will stop the web app. I posted an answer to my own question if anyone is having the same problem. – user628661 Nov 24 '22 at 15:13