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释放属性字典中的待释放资源
- 请求消息
- 响应消息