In some cases, we want to delay the initialization of a dependency. If you are using AUTOFAC, we can inject the lazy
We made a simple makeover of an example offered on AUTOFAC GitHub and ran to see.
Link to the original example Github.com/autofac/examples/tree/master/src/aspnetcoreexample
Micro-changed code
[Route("api/[controller]")]public class ValuesController : Controller{ private readonly Lazy<IValuesService> _valuesService; public ValuesController(Lazy<IValuesService> valuesService) { _valuesService = valuesService; } // GET api/values [HttpGet] public IEnumerable<string> Get() { // Kestrel模式下这里会输出false,实例尚未创建 Console.WriteLine(_valuesService.IsValueCreated); // 调用Lazy<T>的Value属性才真正创建实例 return this._valuesService.Value.FindAll(); }}
Until the current core2.1 version, the own di still does not support lazy loading, and if we try to apply the above code with our own Di, we get an exception, for example:
An unhandled exception occurred while processing the request.
Invalidoperationexception:unable to resolve service for type ' System.lazy ' 1[webapplication9.services.ivaluesservice] ' While attempting to activate ' WebApplication9.Controllers.ValuesController '.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService (IServiceProvider SP, type type, type Requiredby, BOOL isdefaultparameterrequired)
How do you make use of the DI implementation from the core? If we try Baidu, we may find an answer similar to the following.
services.AddTransient(typeof(Lazy<>));
So does this approach solve our problem, in order to simplify the demo code. We create a console program and reference Microsoft.Extensions.DependencyInjection.
class Program{ static void Main(string[] args) { var services = new ServiceCollection(); services.AddScoped<ITestService, TestService>(); services.AddTransient(typeof(Lazy<>)); var serviceProvider = services.BuildServiceProvider(); using (var scope = serviceProvider.CreateScope() ) { var service = scope.ServiceProvider.GetService<Lazy<ITestService>>(); // 这边令人遗憾地输出了true,也就是说,这种方式的延迟注入是失败的 Console.WriteLine(service.IsValueCreated); } }}
When I looked up the stack overflow, I saw the solution, I feel very simple and practical, share to everyone.
Original Sticker Address: Stackoverflow.com/questions/44934511/does-net-core-dependency-injection-support-lazyt
public class lazyloader<t>: lazy<t>{public Lazyloader (IServiceProvider sp): Base (S p.getrequiredservice<t>) {}}class program{static void Main (string[] args) {var services = new Servicecollection (); Services. Addscoped<itestservice, testservice> (); Services. Addscoped (typeof (Lazy<>), typeof (Lazyloader<>)); can also, the difference is not small services. AddTransient (typeof (Lazy<>), typeof (Lazyloader<>)); var serviceprovider = Services. Buildserviceprovider (); using (var scope = Serviceprovider.createscope ()) {var service = scope. Serviceprovider.getservice<lazy<itestservice>> (); Console.WriteLine (service. isvaluecreated); Output false//output true below, deferred injected object and normal injected object, essentially no difference Console.WriteLine (service. Value = = scope. Serviceprovider.getservice<itestservice> ()); } }}
The
Implementation principle is relatively simple, the serviceprovider is injected into the Lazyloader, the Value property of the parent class is called and the delegate is executed, and the corresponding dependent instance is obtained from serviceprovider.