This project demonstrates how dependency injection can be effectively used in astatic class.
Static classes inherently lack dependency injection support, so using a mechanism like
IServiceScope is essential to ensure that service lifetimes are correctly maintained as per the services registered scopes.
When working with scoped or transient services, using
IServiceScope ensures proper disposal of these services after they are used,
preventing resource leaks and preserving intended lifetimes.
- Copy the
ApplicationServiceProviderclass into your project. - Set the application by calling
ApplicationServiceProvider.SetApplication(app)after building your application. - Get a service using
ApplicationServiceProvider.GetRequiredService<T>(out T service)with proper disposal.
To enable dependency injection within a static context, the
ApplicationServiceProvider class is created.
This static service provider holds the application's host instance and provides methods for retrieving services with proper scope management.
Preview:
public static class ApplicationServiceProvider
{
private static IHost? ApplicationHost;
public static void SetApplication(IHost applicationHost);
public static IDisposable GetServiceProvider(out IServiceProvider serviceProvider);
public static IDisposable GetRequiredService<T>(out T service);
}Before using the ApplicationServiceProvider for accessing services, it is necessary to set the application host.
This is achieved by calling ApplicationServiceProvider.SetApplication()
and passing the built application (e.g., an IHost or WebApplication) as a parameter.
This step ensures that the static service provider has access to the application's dependency injection container.
Ensure this is done after creating the application from the builder
but before accessing any services through the ApplicationServiceProvider.
Example usage in Program.cs:
// Create the application (WebApplication)
WebApplication app = builder.Build();
// Set the application host for the service provider
ApplicationServiceProvider.SetApplication(app);Since Scoped and Transient services need to be disposed of after usage, it’s necessary to create a new
ServiceScope each time services are accessed within the static class.
This can be achieved by calling ApplicationHost.Services.CreateScope().
Using ServiceProvider from this serviceScope,
we can access services while guaranteeing that they are disposed of correctly once their usage is complete.
Example:
using (IServiceScope serviceScope = ApplicationHost.Services.CreateScope())
{
return serviceScope.ServiceProvider.GetRequiredService<NestedService>();
}To streamline access to services while ensuring that the ServiceScope is disposed of properly,
ApplicationServiceProvider provides a GetRequiredService method. This method uses an
out parameter for the service instance and returns an IDisposable scope that must be disposed of after usage.
GetRequiredService:
public static IDisposable GetRequiredService<T>(out T service)
where T : notnull
{
if (ApplicationHost is null)
{
throw new InvalidOperationException($"{nameof(ApplicationHost)} is not set. Call {nameof(SetApplication)}() first.");
}
IDisposable serviceScope = GetServiceProvider(out IServiceProvider serviceProvider);
service = serviceProvider.GetRequiredService<T>();
return serviceScope;
}Example usage:
using (ApplicationServiceProvider.GetRequiredService(out NestedService nestedService))
{
nestedService.MakeSound();
}Example when multiple services are required
using (ApplicationServiceProvider.GetServiceProvider(out IServiceProvider serviceProvider))
{
SingletonService singletonService = serviceProvider.GetRequiredService<SingletonService>();
ScopedService scopedService = serviceProvider.GetRequiredService<ScopedService>();
TransientService transientService = serviceProvider.GetRequiredService<TransientService>();
}This pattern ensures that all resources are managed correctly while making service access straightforward and reducing boilerplate code.
The full implementation of ApplicationServiceProvider can be found here:
ApplicationServiceProvider.cs.
You can start this Blazor project and view the dependency injection setup in action on the Static Injection page,
which demonstrates the injection process using StaticClass.cs.