Does .net core dependency injection support Lazy<T>
C#Dependency Injectionasp.net Core.Net CoreLazy InitializationC# Problem Overview
I am trying to use the generic Lazy class to instantiate a costly class with .net core dependency injection extension. I have registered the IRepo type, but I'm not sure what the registration of the Lazy class would look like or if it is even supported. As a workaround I have used this method http://mark-dot-net.blogspot.com/2009/08/lazy-loading-of-dependencies-in-unity.html
config:
public void ConfigureService(IServiceCollection services)
{
services.AddTransient<IRepo, Repo>();
//register lazy
}
controller:
public class ValuesController : Controller
{
private Lazy<IRepo> _repo;
public ValuesController (Lazy<IRepo> repo)
{
_repo = repo;
}
[HttpGet()]
public IActionResult Get()
{
//Do something cheap
if(something)
return Ok(something);
else
return Ok(repo.Value.Get());
}
}
C# Solutions
Solution 1 - C#
Here's another approach which supports generic registration of Lazy<T>
so that any type can be resolved lazily.
services.AddTransient(typeof(Lazy<>), typeof(Lazier<>));
internal class Lazier<T> : Lazy<T> where T : class
{
public Lazier(IServiceProvider provider)
: base(() => provider.GetRequiredService<T>())
{
}
}
Solution 2 - C#
You only need to add a registration for a factory method that creates the Lazy<IRepo>
object.
public void ConfigureService(IServiceCollection services)
{
services.AddTransient<IRepo, Repo>();
services.AddTransient<Lazy<IRepo>>(provider => new Lazy<IRepo>(provider.GetService<IRepo>));
}
Solution 3 - C#
To my opinion, the code below should do the work(.net core 3.1)
services.AddTransient<IRepo, Repo>();
services.AddTransient(typeof(Lazy<>), typeof(Lazy<>));
Solution 4 - C#
Services that are to be fetched in Lazy will be re-introduced by the factory registration method with the new Lazy of the intended service type and provided for its implementation using serviceProvider.GetRequiredService.
services.AddTransient<IRepo, Repo>()
.AddTransient(serviceProvider => new Lazy<IRepo>(() => serviceProvider.GetRequiredService<IRepo>()));
Solution 5 - C#
To register services as lazy
services.AddScoped<Lazy<AService>>();
services.AddScoped<Lazy<BService>>();
Or by creating an extension
static class LazyServiceCollection
{
public static void AddLazyScoped<T>(this IServiceCollection services)
{
services.AddScoped<Lazy<T>>();
}
}
...
services.AddLazyScoped<AService>();
services.AddLazyScoped<BService>();
And use it
[ApiController, Route("lazy")]
public class LazyController : ControllerBase
{
private readonly Lazy<AService> _aService;
private readonly Lazy<BService> _bService;
public LazyController(Lazy<AService> aService, Lazy<BService> bService)
{
_aService = aService;
_bService = bService;
}
[HttpGet("a")]
public ActionResult GetA()
{
_aService.Value.DoWork();
return new OkResult();
}
[HttpGet("b")]
public ActionResult GetB()
{
_bService.Value.DoWork();
return new OkResult();
}
}
Result
Init AService
AService Work