Search code examples
c#asynchronousdependency-injectionidisposable

How to Close a Singleton service that does not implement IDisposable


I have a singleton service that talks to a Service Bus. My problem is that I cannot implement IDisposable elegantly since the "Close" calls to the service bus clients are async - CloseAsync().

Thus, my service class also implements a CloseAsync method which defers to the service bus client's CloseAsync. From what I can gather my options are:

  1. Implement dispose and block while calling CloseAsync on the client. Feels wrong.
  2. Initialise a member variable in startup.cs, add that as a Singleton, use ApplicationLifetime to register a ShutDown handler, and close my clients in there. Seems like overkill. (I've tried this but the code in my ShutDown handler is either not hit, or is not being run)
  3. Simply leave it, since the application is closing anyway. Tempting, but also feels wrong (I like to clean up).

Is there a way to intercept the disposal of services in the DI container (I'm using the standard Microsoft.Extensions.DependencyInjection.ServiceCollection)?

Is it OK to block on an async call within the Dispose method? That way I can make my class self disposing.

Is there another way to do this that I am missing?


Solution

  • If you have a single instance of this object through the lifetime of your application, why do you care about disposing it? When an application closes, its memory space gets reclaimed by the OS, effectively disposing the entire set of application and any resources it may have created.

    IDisposable (explicit disposal) makes sense for types of objects that consume a considerable amount of memory and may be created numerous times (typically in quick succession) during the lifetime of your application; for example, bitmap objects that allocate a large buffer for image data, streams, and other data carrying/manipulating objects that you'd instantiate many times. The sort of things that you'd put in a using block.

    Here's a rule of thumb:

    You need IDisposable only if: each instance of the object consumes significant amount of memory (think tens of megabytes), you need to create and retain many instances at once, or you need to create many instances in very quick succession. In these cases, you'll benefit from manually disposing the object. If these don't fit your use case, then the garbage collector will do a more than sufficient job cleaning up unused resources.

    Should I implement IDisposable on a singleton?

    Thanks @Broots for the useful link.