Does .net core dependency injection support Lazy<T>

南楼画角 提交于 2019-11-27 05:51:29

问题


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());
    }
}

回答1:


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>())
    {
    }
}



回答2:


You only need to do is 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>));
}



回答3:


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>()));



回答4:


I use the Lazier technique above in parts of my code today, but I found I had to REMOVE it when I wanted to use

IEnumerable<Lazy<ISomething>> 

Registration:

services.AddLazier();
services.AddTransient<ISomething, SomeThing1>();
services.AddTransient<ISomething, SomeThing2>();

Injection:

public class IndexModel : PageModel
{
    private IEnumerable<ISomething> _someThings;
    private IEnumerable<Lazy<ISomething>> _someLazyThings;

    public IndexModel(IEnumerable<ISomething> someThings,
        IEnumerable<Lazy<ISomething>> someLazyThings)
    {
        _someThings = someThings;
        _someLazyThings = someLazyThings;
    }
    public void OnGet()
    {
        List<string> names = new List<string>();
        var countSomeThings = _someThings.Count();  // 2 as expected
        var countSomeLazyThings = _someLazyThings.Count(); // 1. huh?
        foreach (var lazyObject in _someLazyThings)
        {
            names.Add(lazyObject.Value.Name);
        }
    }
}

I havent dug into the source to find out exactly why I do not get 2 in my

 IEnumerable<Lazy<ISomething>>

versus

//services.AddLazier();//REMOVED
services.AddTransient<ISomething, SomeThing1>();
services.AddTransient<ISomething, SomeThing2>();
services.AddLazyTransient<ISomething, SomeThing1>();
services.AddLazyTransient<ISomething, SomeThing2>();

Result (works as I want)..

public class IndexModel : PageModel
{
    private IEnumerable<ISomething> _someThings;
    private IEnumerable<Lazy<ISomething>> _someLazyThings;

    public IndexModel(IEnumerable<ISomething> someThings,
        IEnumerable<Lazy<ISomething>> someLazyThings)
    {
        _someThings = someThings;
        _someLazyThings = someLazyThings;
    }
    public void OnGet()
    {
        List<string> names = new List<string>();
        var countSomeThings = _someThings.Count();  // 2 as expected
        var countSomeLazyThings = _someLazyThings.Count(); // 2 as expected
        foreach (var someLazyThing in _someLazyThings)
        {
            names.Add(someLazyThing.Value.Name);
        }
    }
}

the below IServiceCollection extensions show how I register the services.

foreach (var exchange in exchanges)
{
    services.AddTransient<Lazy<ITokenExchangeHandler>>(serviceProvider =>
    {
        return new Lazy<ITokenExchangeHandler>(() =>
        {
            var tokenExchangeHandler = serviceProvider.GetRequiredService<PipelineTokenExchangeHandler>();
            tokenExchangeHandler.Configure(exchange);
            return tokenExchangeHandler;
        });
    }); 
}

public static class AspNetCoreServiceCollectionExtensions
{

    public static IServiceCollection AddLazyTransient<TService, TImplementation>(this IServiceCollection services)
        where TService : class
        where TImplementation : class, TService
    {
        services.AddTransient<TImplementation>();
        services.AddTransient<Lazy<TService>>(serviceProvider =>
        {

            return new Lazy<TService>(() =>
            {
                var impl = serviceProvider.GetRequiredService<TImplementation>();
                return impl;
            });
        });
        return services;
    }

}


来源:https://stackoverflow.com/questions/44934511/does-net-core-dependency-injection-support-lazyt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!