
Dependency Injection (DI) is a powerful pattern for implementing inversion of control, making our applications more modular, testable, and maintainable. .NET offers a built-in DI system that allows us to register and resolve dependencies. However, sometimes, we need more dynamic behavior than straightforward registrations.
In this tutorial, we’ll dive deep into a specialized technique: Using the factory method with AddSingleton
to achieve dynamic service registration.
AddSingleton
, AddScoped
, and AddTransient
?These are extension methods provided by .NET to register services with different lifetimes:
Instead of just providing a type to the AddSingleton
method, we can provide a factory method – a delegate that produces the instance of the service. This factory method can use other registered services and even runtime data.
builder.Services.AddSingleton<IService>(provider =>{var dependency = provider.GetRequiredService<IDependency>();return new MyService(dependency);});
Imagine a scenario where our application’s configuration is stored in a database. Instead of reading it during startup, we want to fetch it dynamically and inject it into our services.
builder.Services.AddSingleton<ISomeService>(provider =>{var getDbSettingsService = provider.GetRequiredService<IGetDbSettingsService>();var dbSettings = getDbSettingsService.ExecuteAsync().Result;return new SomeService(dbSettings);});
Depending on the environment or a certain condition, we might want to return different implementations of an interface.
builder.Services.AddSingleton<IRepository>(provider =>{if (Environment.IsDevelopment()){return new MockRepository();}return new SqlRepository();});
Creating a service might require multiple steps, configurations, or even conditional logic.
Using asynchronous operations within a factory method, like ExecuteAsync().Result
, can lead to deadlocks. It’s often safer to preload such data before setting up the DI container or use synchronous methods if available.
Be cautious about the lifetime of services you resolve in the factory method. Resolving a scoped service inside the factory method of a singleton can lead to unexpected behavior.
The factory method in AddSingleton
(and its siblings AddScoped
and AddTransient
) grants developers the power to dynamically construct services. With this power comes the responsibility to ensure the right lifetimes and handle asynchronous operations properly.
Your insights drive us! For any questions, feedback, or thoughts, feel free to connect:
If you found this guide beneficial, don’t hesitate to share it with your network and help others discover these useful features in DI.
Until the next guide, happy coding!
Quick Links
Legal Stuff