• ASP.NET Web API 框架研究 Controller实例的销毁


      我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释放其资源。在代表请求的HttpRequestMessage属性字典中,有个Key,“Ms_DisposableRequestResources” ,其值是类型List<IDisposable>,用来存放待释放的资源,回顾下ApiController抽象类的方法ExecuteAsync里的代码片段。 

      Request.RegisterForDispose(this)是主要代码,我们看下HttpRequestMessage的相关扩展方法,RegisterForDispose注册销毁资源,DisposeRequestResources释放所有资源。

    public static class HttpRequestMessageExtensions
        {
            //注册一个待销毁的资源列表到请求的属性字典中
            public static void RegisterForDispose(this HttpRequestMessage request, IDisposable resource)
            {
                if (request == null)
                {
                    throw Error.ArgumentNull("request");
                }
    
                if (resource == null)
                {
                    return;
                }
    
                List<IDisposable> trackedResources = GetRegisteredResourcesForDispose(request);
    
                trackedResources.Add(resource);
            }
    
            //一次性注册多个待销毁的资源列表到请求的属性字典中
            public static void RegisterForDispose(this HttpRequestMessage request, IEnumerable<IDisposable> resources)
            {
                if (request == null)
                {
                    throw Error.ArgumentNull("request");
                }
    
                if (resources == null)
                {
                    throw Error.ArgumentNull("resources");
                }
    
                List<IDisposable> trackedResources = GetRegisteredResourcesForDispose(request);
    
                foreach (IDisposable resource in resources)
                {
                    if (resource != null)
                    {
                        trackedResources.Add(resource);
                    }
                }
            }
    
            //释放资源列表(RegisterForDispose方法注册)里的所有资源
            public static void DisposeRequestResources(this HttpRequestMessage request)
            {
                if (request == null)
                {
                    throw Error.ArgumentNull("request");
                }
    
                List<IDisposable> resourcesToDispose;
                if (request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out resourcesToDispose))
                {
                    foreach (IDisposable resource in resourcesToDispose)
                    {
                        try
                        {
                            resource.Dispose();
                        }
                        catch
                        {
                            // ignore exceptions
                        }
                    }
                    //清空列表
                    resourcesToDispose.Clear();
                }
            }
    
            //从当前请求中获取所有待销毁的资源的列表
            public static IEnumerable<IDisposable> GetResourcesForDisposal(this HttpRequestMessage request)
            {
                if (request == null)
                {
                    throw Error.ArgumentNull("request");
                }
    
                return GetRegisteredResourcesForDispose(request);
            }
    
            //从当前请求中获取所有待销毁的资源的列表
            private static List<IDisposable> GetRegisteredResourcesForDispose(HttpRequestMessage request)
            {
                List<IDisposable> registeredResourcesForDispose;
                //从属性字典中,获取指定Key的值
                if (!request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out registeredResourcesForDispose))
                {
                    registeredResourcesForDispose = new List<IDisposable>();
                    request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey] = registeredResourcesForDispose;
                }
                return registeredResourcesForDispose;
            }
        }

    一、WebHost 模式下的资源销毁

      ASP.NET Web API用于“处理请求、回复响应”的 HttpMessageHandler管道是由 HttpControllerHandler创建的,后者根据当前HTTP上下文创建一个表示当前请求的HttpRequestMessage对象并传入这个管道进行处理 。在整个管道完成对请求的处理并最终对请求予以响应之后 ,HttpControllerHandler会负责完成资源释放有关的工作

    工作。回顾下HttpControllerHandler,方法的代码:

    public  class HttpControllerHandler:HttpTaskAsyncHandler
        {
            //省略其他成员
    
            public HttpControllerHandler(RouteData routeData)
                : this(routeData, GlobalConfiguration.DefaultServer)
            {
            }
    
            public override Task ProcessRequestAsync(HttpContext context)
            {
                return ProcessRequestAsyncCore(new HttpContextWrapper(context));
            }
    
            internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase)
            {
                HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? ConvertRequest(contextBase);
    
                // Add route data
                request.SetRouteData(_routeData);
                CancellationToken cancellationToken = contextBase.Response.GetClientDisconnectedTokenWhenFixed();
                HttpResponseMessage response = null;
    
                try
                {
                    //创建消息处理管道,并执行
                    response = await _server.SendAsync(request, cancellationToken);
                    //异步执行完成
                    await CopyResponseAsync(contextBase, request, response, _exceptionLogger.Value, _exceptionHandler.Value,
                        cancellationToken);
                }
                catch (OperationCanceledException)
                {
                   
                    contextBase.Request.Abort();
                }
                finally
                {
                    //1.调用方法DisposeRequestResources释放属性字典中的待释放资源
              request.DisposeRequestResources();
              //2.释放请求消息
               request.Dispose();
              //3.释放响应消息
                    if (response != null)
                    {
                        response.Dispose();
                    }
                }
            }
        }

      从代码可知道,创建管道并执行完成后,在finally代码块里释放了三种资源,

    • 调用方法DisposeRequestResources释放属性字典中的待释放资源
    • 请求消息
    • 响应消息

    二、Self Host模式下的资源销毁

      Self Host模式下的请求的监听、接收和响应是通过HttpBinding创建的信道栈来完成的,该信道栈处理的消息类型为HttpMessage,具体代表请求消息和响应消息的HttpMesmge分别是对HttpRequestMessage和Message对象的封装。WCF中表示消息的Message本身就是一个需要最终被释放的对象,在针对它的处理结束之后会调用其Close或 者 Dispose方法对它进行资源释放的工作。再看下代码段

    internal sealed class HttpMessage : Message
        {
            //省略其他成员
            protected override void OnClose()
            {
                base.Close();
                if (_request != null)
                {
                    //1.调用DisposeRequestResources,释放属性字典中注册的资源
                    _request.DisposeRequestResources();
     //2.释放请求消息
                    _request.Dispose();
                    _request = null;
                }
                //3.释放响应消息
                if (_response != null)
                {
                    _response.Dispose();
                    _response = null;
                }
            }
        }
     internal sealed class Message : IDisposable
        {
            protected virtual void OnClose()
            {
            }
    
            public void Close()
            {
                if (this.state != MessageState.Closed)
                {
                    this.state = MessageState.Closed;
                    //调用OnClose()
                    this.OnClose();
    if (!System.ServiceModel.DiagnosticUtility.ShouldTraceVerbose)
                        return;
                    TraceUtility.TraceEvent(TraceEventType.Verbose, 524304, System.ServiceModel.SR.GetString("TraceCodeMessageClosed"), this);
                }
                else
                {
                    if (!System.ServiceModel.DiagnosticUtility.ShouldTraceVerbose)
                        return;
                    TraceUtility.TraceEvent(TraceEventType.Verbose, 524305, System.ServiceModel.SR.GetString("TraceCodeMessageClosedAgain"), this);
                }
            }
            //Dispose模式用法
            void IDisposable.Dispose()
            {
                //调用Close()
                this.Close();
            }
       }

      从代码可以知道,在HttpMessage的Dispose方法里,会调用代码也是释放三种资源

    • 调用方法DisposeRequestResources释放属性字典中的待释放资源
    • 请求消息
    • 响应消息
  • 相关阅读:
    将Python脚本变为命令行--click模块使用
    MongoDB大批量读写数据优化记录
    [转]MongoDB更新操作replaceOne()实例讲解
    pip 18.1: pipenv graph results in ImportError: cannot import name 'get_installed_distributions'
    mitmdump 屏蔽443错误
    python3 操作appium
    appium-Could not obtain screenshot: [object Object]
    scrapy主动触发关闭爬虫
    匿名函数
    装饰器1、无参数的装饰器 2、有参数的装饰器 3、装饰器本身带参数的以及如果函数带return结果的情况
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8082444.html
Copyright © 2020-2023  润新知