问题
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