• Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?


    Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?

    在asp.net core中的DI生命周期有一个Scoped是根据请求走的,也就是说在处理一次请求时,Scope生命周期所提供的服务是同一个实例。它是用IServiceScope是实现的。但是我们要知道何时构建的IServiceScope以及IServiceScope何时被销毁掉
    先说结论IServiceScope是根据当前的RequestServicesFeature内作为_scope成员存在的,只要知道RequestServicesFeature何时创建,何时销毁就了解整http request DI的生命周期

    netcore中DI生命周期。

    在net core 默认的DI中你直接build 出来的servicepProvider 用它去获取的实例对象Scoped & Singleton 是具有相同生命周期的。
    如果需要有Scoped生命周期的实例,你需要通过serviceProvider创建一个IServiceScope实例,然后通过该实例获取到的服务实例会跟着IServiceScope一同销毁从而达到Scoped生命周期。

    DI生命周期案例 1
    ServiceCollection serviceCollection = new ServiceCollection();
    serviceCollection.AddSingleton<MySingletonClass>();
    serviceCollection.AddScoped<MyScopedClass>();
    serviceCollection.AddTransient<MyTransientClass >();
    var servicepProvider = serviceCollection.BuildServiceProvider();
    using (IServiceScope scope = servicepProvider.CreateScope(), scope2 = servicepProvider.CreateScope())
    {
        var scopeObj1 = scope.ServiceProvider.GetService<MyScopedClass>();
        var scopeObj2 = scope2.ServiceProvider.GetService<MyScopedClass>();
        Console.WriteLine(object.ReferenceEquals(scopeObj1, scopeObj2)); //false
    }
    //Scoped Constructor
    //Scoped Constructor
    //False
    //Scoped Dispose
    //Scoped Dispose
    Console.ReadLine();
    
    public class MyScopedClass : IDisposable
    {
        public MyScopedClass() => Console.WriteLine("Scoped Constructor");
        public void Dispose() => Console.WriteLine("Scoped Dispose");
    }
    
    public class MyTransientClass : IDisposable
    {
        public MyTransientClass() => Console.WriteLine("Transient Constructor");
    
        public void Dispose() => Console.WriteLine("Transient Dispose");
    }
    
    public class MySingletonClass : IDisposable
    {
        public MySingletonClass() => Console.WriteLine("Singleton Constructor");
    
        public void Dispose() => Console.WriteLine("Singleton Dispose");
    }
    
    RequestServicesFeature

    为什么说http request DI 的生命周期是根据RequestServicesFeature来的。通过DI生命周期案例了解到需要创建一个scope生命周期,要有一个IServiceScope实例。
    那么在http feature中RequestServicesFeature做了对该接口的封装。也用于提供RequestSerivces服务。

    1. IServiceScope的创建: HttpContext获取RequstServiceProivder是根据RequestServicesFeature.RequestServices。在RequestServices属性的get方法内创建_scope。并返回给该scope对应的ServiceProvide供后续使用。
    2. IServiceScope的销毁:在RequestServicesFeature.Dispose 方法内又调用了_scope属性(IServiceScope)的同名方法从而进行销毁由此提供的所有service。那么只要销毁了当前请求的RequestServicesFeature 实例就销毁了。当前http requst 的scope生命周期的所有服务。
    RequestServicesFeature 是何时被销毁的。
    1. HttpProtocol.ProcessRequests 方法内调用await FireOnCompleted();
    2. FireOnCompleted内部会循环执行 Stack<KeyValuePair<Func<object, Task>, object>>? _onCompleted;堆栈委托
    3. requestServiceFeature.Dispose在此刻被调用,其内部Dispose了IServiceScope。自此ServiceScope生命周期结束。
    RequestServicesFeature 简化代码
    public class RequestServicesFeature : IServiceProvidersFeature, IDisposable, IAsyncDisposable
    {
        private IServiceScope? _scope;
        private readonly HttpContext _context;
     
        public RequestServicesFeature(HttpContext context, IServiceScopeFactory? scopeFactory)
        {
            _context = context;
            _scopeFactory = scopeFactory;
        }
     
        public IServiceProvider RequestServices
        {
            get
            {
                _context.Response.RegisterForDisposeAsync(this);
                _scope = _scopeFactory.CreateScope();
                _requestServices = _scope.ServiceProvider;
                return _requestServices!;
            }
    
        }
     
        /// <inheritdoc />
        public ValueTask DisposeAsync()
        {
            switch (_scope)
            {
                case IAsyncDisposable asyncDisposable:
                    var vt = asyncDisposable.DisposeAsync();
                    if (!vt.IsCompletedSuccessfully)
                    {
                        return Awaited(this, vt);
                    }
                    vt.GetAwaiter().GetResult();
                    break;
                case IDisposable disposable:
                    disposable.Dispose();
                    break;
            }
        }
    }
    
    HttpProtocol

    该类是处理http协议的 ProcessRequests作为重要方法之一,用来使用我们构建好的IHttpApplication 处理request
    httpontext的创建,以及我们编排好的http中间件管道都是在这里被执行的。同时调用FireOnCompleted, RequestServicesFeature就是在这里被销毁的。

    private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application) where TContext : notnull
    {
        while (_keepAlive)
        {
            var context = application.CreateContext(this);
            // Run the application code for this request
            await application.ProcessRequestAsync(context);
            if (_onCompleted?.Count > 0)
            {
                await FireOnCompleted();
            }
            application.DisposeContext(context, _applicationException);
        }
    }
    
    protected Task FireOnCompleted()
        {
            var onCompleted = _onCompleted;
            if (onCompleted?.Count > 0)
            {
                return ProcessEvents(this, onCompleted);
            }
     
            return Task.CompletedTask;
     
            static async Task ProcessEvents(HttpProtocol protocol, Stack<KeyValuePair<Func<object, Task>, object>> events)
            {
                while (events.TryPop(out var entry))
                {
                    try
                    {
                        await entry.Key.Invoke(entry.Value);
                    }
                    catch (Exception ex)
                    {
                        protocol.Log.ApplicationError(protocol.ConnectionId, protocol.TraceIdentifier, ex);
                    }
                }
            }
        }
    
    RequestServicesFeature 是如何注册到HttpProtocol _onCompleted;堆栈委托中的

    HttpProtocol委托堆栈中 RequestServicesFeature 是什么时候被注册进去的呢?

    1. RequestServicesFeature.RequestServices属性的Get方法调用了方法内有一句这样的代码 _context.Response.RegisterForDisposeAsync(this);
    2. HttpResponse的RegisterForDisposeAsync调用了抽象方法abstract void OnCompleted。实现该方法的是在完成的DefaultHttpResponse
    3. DefaultHttpResponse的OnCompleted把委托注册到HttpProtocol.OnCompleted方法注册到_onCompleted中,实际代码体现为 HttpResponseFeature.OnCompleted(callback, state);这里HttpResponseFeature.就是就是HttpProtocol,(HttpProtoccol是个IFeatureCollection接口的实现。)
  • 相关阅读:
    关于医学的一点想法
    我的ArcGis9.3 到Arcgis10.0 升级步骤
    最近一月的娱乐生活:看电影,玩游戏
    最近一月的娱乐生活:看电影,玩游戏
    5年技术学习历程的回顾
    5年技术学习历程的回顾
    网站开发的技术选型问题
    网站开发的技术选型问题
    学技术真累
    Java实现 LeetCode 200 岛屿数量
  • 原文地址:https://www.cnblogs.com/hts92/p/15856399.html
Copyright © 2020-2023  润新知