一、HttpContext
对当前上下文的抽象解除了管道对具体服务器类型的依赖, 这使我们为ASP.NET Core应用自由地选择寄宿方式,而不是像传统的ASP.NET应用一样只能寄宿在IIS之中。抽象HTTP上下文的目的是为了实现对请求处理流程的抽象,只有这样我们才能将针对请求的某项操作体现在一个标准的中间件上,有这个这个标准化的中间件才有所谓的请求处理管道。
ASP.NET Core通过具有如下所示的HttpContext类来表示这么一个抽象的HTTP上下文。对于一个HttpContext对象来说,它的核心体现在用于描述请求和响应的Request和Response属性之上。除此之外,我们还可以通过获取与当前请求相关的其他上下文信息,比如用来控制用户认证的AuthenticationManager对象和代表当前请求用户的ClaimsPrincipal对象,描述当前HTTP连接的ConnectionInfo对象和用于控制WebSocket的WebSocketManager。我们还可以获取并控制当前会话,也可以获取或者设置调试追踪的ID。
namespace Microsoft.AspNetCore.Http { // // 摘要: // Encapsulates all HTTP-specific information about an individual HTTP request. public abstract class HttpContext { protected HttpContext(); // // 摘要: // Gets the collection of HTTP features provided by the server and middleware available // on this request. public abstract IFeatureCollection Features { get; } // // 摘要: // Gets the Microsoft.AspNetCore.Http.HttpRequest object for this request. public abstract HttpRequest Request { get; } // // 摘要: // Gets the Microsoft.AspNetCore.Http.HttpResponse object for this request. public abstract HttpResponse Response { get; } // // 摘要: // Gets information about the underlying connection for this request. public abstract ConnectionInfo Connection { get; } // // 摘要: // Gets an object that manages the establishment of WebSocket connections for this // request. public abstract WebSocketManager WebSockets { get; } // // 摘要: // Gets or sets the user for this request. public abstract ClaimsPrincipal User { get; set; } // // 摘要: // Gets or sets a key/value collection that can be used to share data within the // scope of this request. public abstract IDictionary<object, object?> Items { get; set; } // // 摘要: // Gets or sets the System.IServiceProvider that provides access to the request's // service container. public abstract IServiceProvider RequestServices { get; set; } // // 摘要: // Notifies when the connection underlying this request is aborted and thus request // operations should be cancelled. public abstract CancellationToken RequestAborted { get; set; } // // 摘要: // Gets or sets a unique identifier to represent this request in trace logs. public abstract string TraceIdentifier { get; set; } // // 摘要: // Gets or sets the object used to manage user session data for this request. public abstract ISession Session { get; set; } // // 摘要: // Aborts the connection underlying this request. public abstract void Abort(); } }
RequestAborted属性:当客户端中止请求(如请求超时)时,我们可以通过RequestAborted属性返回的CancellationToken对象接收到通知,进而及时中止正在进行的请求处理操作。
Items属性:如果需要针对整个管道共享一些与当前上下文相关的数据,我们可以将它保存在通过Items属性表示的字典中。
RequestServices属性:返回针对当前请求的IServiceProvider对象,该对象的生命周期与表示当前请求上下文的HttpContext对象绑定。
Request属性:HttpContext对象中,表示请求的成员
Response属性:HttpContext对象中,表示响应的成员
二、获取HttpContext上下文
如果第三方组件需要获取表示当前请求上下文的HttpContext对象,就可以通过注入IHttpContextAccessor服务来实现。
1、startup中注入IHttpContextAccessor
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
2、获取HttpContext上下文
private IHttpContextAccessor _accessor; public WeatherForecastController(IHttpContextAccessor accessor) { _accessor = accessor; } [HttpGet] public IEnumerable<WeatherForecast> Get() { var httpcontext = _accessor.HttpContext; }
三、HttpContext上下文的创建与释放
利用IHttpContextAccessor服务获取当前HttpContext上下文的前提是上下文已经被赋值,在默认情况下,该属性是通过默认注册的IHttpContextFactory服务赋值的。
public interface IHttpContextFactory { HttpContext Create(IFeatureCollection featureCollection); void Dispose(HttpContext httpContext); }
管道在开始处理请求前对HttpContext上下文的创建,以及请求处理完成后对它的回收释放都是通过IHttpContextFactory对象完成的。IHttpContextFactory接口定义了如下两个方法:
-
Create方法会根据提供的特性集合来创建HttpContext对象
-
Dispose方法则负责将提供的HttpContext对象释放
ASP.NET Core框架提供DefaultHttpContextFactory类型作为对IHttpContextFactory接口的默认实现,HttpContext上下文的 DefaultHttpContext对象就是由它创建的。
public class DefaultHttpContextFactory : IHttpContextFactory { private readonly IHttpContextAccessor _httpContextAccessor; private readonly FormOptions _formOptions; private readonly IServiceScopeFactory _serviceScopeFactory; public DefaultHttpContextFactory(IServiceProvider serviceProvider) { _httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>(); _formOptions = serviceProvider.GetRequiredService<IOptions<FormOptions>>().Value; _serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>(); } public HttpContext Create(IFeatureCollection featureCollection) { var httpContext = CreateHttpContext(featureCollection); if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = httpContext; } httpContext.FormOptions = _formOptions; httpContext.ServiceScopeFactory = _serviceScopeFactory; return httpContext; } private static DefaultHttpContext CreateHttpContext(IFeatureCollection featureCollection) { if (featureCollection is IDefaultHttpContextContainer container) { return container.HttpContext; } return new DefaultHttpContext(featureCollection); } public void Dispose(HttpContext httpContext) { if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = null; } } }
在IHttpContextAccessor服务被注册的情况下,ASP.NET Core框架将调用第二个构造函数来创建HttpContextFactory对象。在Create方法中,它根据提供的IFeatureCollection对象创建一个DefaultHttpContext对象,在返回该对象之前,它会将该对象赋值给IHttpContextAccessor对象的HttpContext属性。HttpContextFactory在创建出DefaultHttpContext对象并将它设置到IHttpContextAccessor对象的HttpContext属性上之后,它还会设置DefaultHttpContext对象的FormOptions属性和ServiceScopeFactory属性,前者表示针对表单的配置选项,后者是用来创建服务范围的工厂。当Dispose方法执行的时候,DefaultHttpContextFactory对象会将IHttpContextAccessor服务的HttpContext属性设置为Null。