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
ApplicationServiceProvider
class 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.