HttpContext探究之RequestServices
在一篇随笔中提到了中间件的构造方式,主要有两种,第一种是直接从容器里面获取,第二种是构造函数的参数从容器里面获取,这两者都离不开容器,也就是serviceprovide,而RequestService则是里面重要的内容标签:RequestServices,public,探究,context,ServiceProvidersFeature,HttpContext,httpContex From: https://www.cnblogs.com/guoxiaotian/p/18234191RequestServices是什么
HttpContext.RequestServices
是一个IServiceProvider
实例,它代表了当前 HTTP 请求的作用域服务容器。这个服务容器是在请求处理管道的早期阶段创建的,并附加到 HttpContext 对象上。说人话就是随着httpcontext一起创建的。如何创建
首先看看
HttpContext
结构 :httpcontext
默认实现是defaulthttpcontext
,代码中其他的都删除了,只保留了requestservice相关以及构造函数。
defaulthttpcontext
由IHttpContextFactory
的默认实现类DefaultHttpContextFactory
创建DefaultHttpContext
public sealed class DefaultHttpContext : HttpContext { //省略一堆代码 private static readonly Func<DefaultHttpContext, IServiceProvidersFeature> _newServiceProvidersFeature = context => new RequestServicesFeature(context, context.ServiceScopeFactory); private readonly DefaultHttpRequest _request; private readonly DefaultHttpResponse _response; public DefaultHttpContext() : this(new FeatureCollection(DefaultFeatureCollectionSize)) { Features.Set<IHttpRequestFeature>(new HttpRequestFeature()); Features.Set<IHttpResponseFeature>(new HttpResponseFeature()); Features.Set<IHttpResponseBodyFeature>(new StreamResponseBodyFeature(Stream.Null)); } public IServiceScopeFactory ServiceScopeFactory { get; set; } = default!; private IServiceProvidersFeature ServiceProvidersFeature => _features.Fetch(ref _features.Cache.ServiceProviders, this, _newServiceProvidersFeature)!; public override IServiceProvider RequestServices { get { return ServiceProvidersFeature.RequestServices; } set { ServiceProvidersFeature.RequestServices = value; } } }
DefaultHttpContextFactory
public class DefaultHttpContextFactory : IHttpContextFactory { private readonly IHttpContextAccessor? _httpContextAccessor; private readonly FormOptions _formOptions; private readonly IServiceScopeFactory _serviceScopeFactory; public DefaultHttpContextFactory(IServiceProvider serviceProvider) { // May be null _httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>(); _formOptions = serviceProvider.GetRequiredService<IOptions<FormOptions>>().Value; _serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>(); } internal IHttpContextAccessor? HttpContextAccessor => _httpContextAccessor; public HttpContext Create(IFeatureCollection featureCollection) { ArgumentNullException.ThrowIfNull(featureCollection); var httpContext = new DefaultHttpContext(featureCollection); Initialize(httpContext, featureCollection); return httpContext; } internal void Initialize(DefaultHttpContext httpContext, IFeatureCollection featureCollection) { httpContext.Initialize(featureCollection); if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = httpContext; } httpContext.FormOptions = _formOptions; httpContext.ServiceScopeFactory = _serviceScopeFactory; } }
DefaultHttpContextFactory.Create
方法里面创建DefaultHttpContext, 并进行初始化赋值:httpContext.ServiceScopeFactory = _serviceScopeFactory;
而_serviceScopeFactory
是从服务中获取的来的,同时也是注册为单例生命周期。接着在
DefaultHttpContext
中 利用serviceScopeFactory 去构建一个叫做Func<DefaultHttpContext, IServiceProvidersFeature> _newServiceProvidersFeature = context => new RequestServicesFeature(context, context.ServiceScopeFactory)
;一个这样的委托,同时使用一个叫做
ServiceProvidersFeature
的属性获取去RequestServicesFeature
private IServiceProvidersFeature ServiceProvidersFeature => _features.Fetch(ref _features.Cache.ServiceProviders, this, _newServiceProvidersFeature)!;
看起来很绕,实际上确实有点绕,:)
_features.Fetch(ref _features.Cache.ServiceProviders, this, _newServiceProvidersFeature)!;
说人话就是先从缓存的ref _features.Cache.ServiceProviders获取,如果没有的话,就调用_newServiceProvidersFeature
这个委托获取,参数就是this,即defaulthttpcontext。然后赋值给_features.Cache.ServiceProviders**核心要点保证获取的是同一个 **
ServiceProvidersFeature `,
不会每次都创建一个新的 IServiceProvidersFeature,这一点很重要。最后就是
RequestServices
,直接从ServiceProvidersFeature.RequestServices
中获取public override IServiceProvider RequestServices { get { return ServiceProvidersFeature.RequestServices; } set { ServiceProvidersFeature.RequestServices = value; } } public IServiceProvider RequestServices { get { if (!_requestServicesSet && _scopeFactory != null) { _context.Response.RegisterForDisposeAsync(this); _scope = _scopeFactory.CreateScope(); _requestServices = _scope.ServiceProvider; _requestServicesSet = true; } return _requestServices!; } set { _requestServices = value; _requestServicesSet = true; } }
同样也是为了保证每次获得的
_requestServices
都是同一个,初始化的时候是使用_scopeFactory.CreateScope(); 即创建了一个服务域,然后本次请求的所有服务都从此容器中获取,所以范围单例的服务生命周期默认为一次请求,就可以理解了。有什么用
上面说到一次请求中的所有服务都从requestServices 中获取,这就是他最大的作用,作为一个依赖注入容器,我们看看它是如何被使用的。
比如上篇文章里面涉及到了如何构建基于接口实现的中间件
public RequestDelegate CreateMiddleware(RequestDelegate next) { return async context => { //di中获取middlewareFactory var middlewareFactory = (IMiddlewareFactory?)context.RequestServices.GetService(typeof(IMiddlewareFactory)); //省略一些判断,利用middlewareFactory构造我们的中间件,实际上就是从di中获取, //只不过包裹了一层 var middleware = middlewareFactory.Create(_middlewareType); //省略一些判断 try { await middleware.InvokeAsync(context, next); } finally { middlewareFactory.Release(middleware); } }; }
这里的
IMiddlewareFactory
就是从context.RequestServices
中获取的,也说明了此种类型中间件是每次请求都会被创建一次,而不是整个应用生命周期只创建一次。同时还有我们的controller类的构建,此篇
有提到,相关创建controller代码:
public object CreateController(ControllerContext context) { //重点代码 var controller = _controllerActivator.Create(context); oreach (var propertyActivator in _propertyActivators) { propertyActivator.Activate(context, controller); } return controller; } public object Create(ControllerContext controllerContext) { //核心代码 删除了一些代码 var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo; var serviceProvider = controllerContext.HttpContext.RequestServices; return _typeActivatorCache.CreateInstance<object>(serviceProvider, controllerTypeInfo.AsType()); }
看到代码中我们的controller对象也是通过
controllerContext.HttpContext.RequestServices
提供的构造参数去构建。总结
大概介绍了一下httpcotext的RequestServices,是如何根据每次请求被创建的,以及有什么样的作用,以后写bug应该会更加得心应手把 :)
参考文章:
微软官方文档