Disposing Injected Services (or: Using Dependency Injection Scopes)

The DI container Microsoft.Extensions.DependencyInjection disposes registered services automatically. It’s just the question when the dispose takes place. Automatic dispose of transient and scoped services happen at the end of a scope. With ASP.NET Core applications, scopes are created with every HTTP request – after the request, services are disposed.
I’m using Microsoft.Extensions.DependencyInjection not only with ASP.NET Core and EF Core, but also with XAML-based applications (UWP, WPF, and Xamarin). Here it can be useful to create scopes with view-models that are associated with a XAML page. As soon as the page is not needed anymore, the scope is disposed and with it all the services from the current scope as well as all transient services. Singleton services are kept alive. Singletons are always associated with the root container – and only disposed when the root container is disposed.

This article shows creating and using DI scopes with XAML-based applications.

Recycling waste and garbage

In case you use your own factory to pass service instances to the container, you still need to dispose the services yourself.

Service Registrations with Microsoft.Extensions.DependencyInjection

The container coming with .NET Core, Microsoft.Extensions.DependencyInjection, is deeply used with ASP.NET Core and EF Core. However, because it is shipped in a .NET Standard library, you can use it with other application types as well. Since the availability of NET Core, I’m using this DI container not only with ASP.NET Core, but also with WPF, UWP, and Xamarin applications.

In the UWP sample application, the container is created in the AppServices class. Here, scoped, and transient services are registered.

  • A transient service is instantiated every time an instance is requested.
  • A singleton service is instantiated only once. On requests of this type, always the same instance is returned.
  • With scoped registrations, an instance is created within every scope where the type is requested.

Transient service registration should be the preferred method to register services. Scoped and singleton services are useful to share state.

One more note to the lifetime of services:

A service injected should have the same or longer lifetime than the service where it is injected. For example, you can inject a singleton service within a transient service. The singleton service has a longer lifetime than the transient service. You cannot inject a transient service within a singleton. This would expand the lifetime of the transient service. Doing this with Microsoft.Extensions.DependencyInjection results in a exception.

What is a Scope?

With ASP.NET Core, DI scopes are created with every HTTP request. When a service is requested within a HTTP request (in middleware, controllers, services, or views), and the service is registered as scoped service, the same instance is used in case the same type is requested multiple times within a request. For example, if a scoped service is injected within a controller, a service, and within a view, the same instance is returned. With the flow of another HTTP request, a different instance is used. When the request is completed, the scope is disposed. Disposing the scope results in disposing of all transient and scoped services that are associated with that scope.

Singleton services are never associated with a scope – they are associated with the root container, and disposed when the root container is disposed.

Disposable Services and View-Models

Some services and view-models need to be disposed. For example, the MasterDetailViewModel base class implements the interface IDisposable to unsubscribe from events:

Injection of services into services and view-models

The BooksService class needs an implementation of the IBooksRepository interface. This is injected via constructor injection and assigned to a readonly member field. The base class of BooksService, the abstract class ItemsService needs some more services that are passed to the constructor of the base class.

Similar to the BooksService, the BooksViewModel class defines services to be injected via the constructor:

Instantiating view-models in a scope

The view-model is associated to a page by assigning it to the ViewModel property of the page. Here, a DI scope is created by invoking the CreateScope method of the ServiceProvider. This scope is disposed when the page is unloaded which is handled in the Unloaded event handler method. Because the BooksViewModel class is registered as transient service in the container, the instance is associated with the newly created scope, and disposed when the scope is disposed. All the transient and scoped services that are created directly or indirectly when the BooksViewModel is instantiated, are disposed as well when the scope is disposed.

Disposing in Reverse Creation Order

In previous versions of the DI container, the DI container had a bug that is relevant if the disposing of services disposing services in the wrong order. This has been fixed with dispose services in reverse creation order.

See my ServicesLifetime sample of my book Professional C# 7 and .NET Core 2.0 creates multiple scopes with disposable services in a simple console application and uses the services.

Running the application, you can see that the services C and A are disposed when the scope is disposed – in the reverse creation order. Service A is a scoped service, and service B a transient service. Service B is disposed with the disposal of the root container – this service is registered as singleton:

UsingScoped
ctor ServiceA, 1
A, 1
A, 1
ctor ServiceB, 2
B, 2
ctor ServiceC, 3
C, 3
ctor ServiceC, 4
C, 4
disposing ServiceC, 4
disposing ServiceC, 3
disposing ServiceA, 1
end of scope1
ctor ServiceA, 5
A, 5
B, 2
ctor ServiceC, 6
C, 6
disposing ServiceC, 6
disposing ServiceA, 5
end of scope2

disposing ServiceB, 2

Summary

Using dependency injection makes the code a lot more maintainable. You can easily see dependencies. Unit tests can be done easily. Using services that are injected, functionality typically is better separated. With this article you’ve seen that you do not need to invoke the Dispose method of services yourself – this is dealt with from the container. You just need to create scopes to early dispose transient and scoped services.

If this information helped you with the architecture of your application or fixed issues, consider buying me multiple coffees. This helps staying up longer and writing more articles šŸ™‚

Buy Me A Coffee

More Information

See the complete XAML app sample with UWP, WPF, and Xamarin using dependency injection BooksSample. This sample will be extended over time to show several features of the library Generic.ViewModels.

The complete services lifetime sample is in the Professional C# 7 and .NET Core 2.0 repository.

My new book Professional C# 7 and .NET Core 2.0 has a complete chapter dedicated to dependency injection: chapter 20, Dependency Injection.

More information on XAML and writing UWP applications is in my book Professional C# 7 and .NET Core 2.0, and in my Programming Windows Apps workshops.

Enjoy learning and programming!

Christian

Advertisements

2 thoughts on “Disposing Injected Services (or: Using Dependency Injection Scopes)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.