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

  我们知道项目中创建的Controller,如ProductController都继承自ApiController抽象类,其又实现了接口IDisposable,所以,框架中自动调用Dispose方法来释放其资源。在代表请求的HttpRequestMessage属性字典中,有个Key,“Ms_DisposableRequestResources” ,其值是类型List,用来存放待释放的资源,回顾下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释放属性字典中的待释放资源
  • 请求消息
  • 响应消息
  • 相关内容推荐