DotNetCore深入了解之二HttpContext类
当KestrelServer启动时,会绑定相应的IP地址,同时在绑定时将加入HttpConnectionMiddleware作为终端连接的中间件。

1 public async Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken) 2 { 3 try 4 { 5 ... 6 7 async Task OnBind(ListenOptions endpoint) 8 { 9 // Add the HTTP middleware as the terminal connection middleware 10 endpoint.UseHttpServer(endpoint.ConnectionAdapters, ServiceContext, application, endpoint.Protocols); 11 12 var connectionDelegate = endpoint.Build(); 13 14 // Add the connection limit middleware 15 if (Options.Limits.MaxConcurrentConnections.HasValue) 16 { 17 connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync; 18 } 19 20 var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate); 21 var transport = _transportFactory.Create(endpoint, connectionDispatcher); 22 _transports.Add(transport); 23 24 await transport.BindAsync().ConfigureAwait(false); 25 } 26 27 await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false); 28 } 29 30 ... 31 }

1 public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols) 2 { 3 var middleware = new HttpConnectionMiddleware<TContext>(adapters, serviceContext, application, protocols); 4 return builder.Use(next => 5 { 6 return middleware.OnConnectionAsync; 7 }); 8 }
当请求抵达此中间件时,在其OnConnectionAsync方法里会创建HttpConnection对象,并通过该对象处理请求

1 public async Task OnConnectionAsync(ConnectionContext connectionContext) 2 { 3 ... 4 5 var connection = new HttpConnection(httpConnectionContext); 6 _serviceContext.ConnectionManager.AddConnection(httpConnectionId, connection); 7 8 try 9 { 10 var processingTask = connection.ProcessRequestsAsync(_application); 11 12 ... 13 } 14 ... 15 }
ProcessRequestsAsync方法内部会根据HTTP协议的不同创建Http1Connection或者Http2Connection对象,一般为Http1Connection。

1 public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication) 2 { 3 try 4 { 5 ... 6 7 lock (_protocolSelectionLock) 8 { 9 // Ensure that the connection hasn't already been stopped. 10 if (_protocolSelectionState == ProtocolSelectionState.Initializing) 11 { 12 switch (SelectProtocol()) 13 { 14 case HttpProtocols.Http1: 15 // _http1Connection must be initialized before adding the connection to the connection manager 16 requestProcessor = _http1Connection = CreateHttp1Connection(_adaptedTransport, application); 17 _protocolSelectionState = ProtocolSelectionState.Selected; 18 break; 19 case HttpProtocols.Http2: 20 // _http2Connection must be initialized before yielding control to the transport thread, 21 // to prevent a race condition where _http2Connection.Abort() is called just as 22 // _http2Connection is about to be initialized. 23 requestProcessor = CreateHttp2Connection(_adaptedTransport, application); 24 _protocolSelectionState = ProtocolSelectionState.Selected; 25 break; 26 case HttpProtocols.None: 27 // An error was already logged in SelectProtocol(), but we should close the connection. 28 Abort(ex: null); 29 break; 30 default: 31 // SelectProtocol() only returns Http1, Http2 or None. 32 throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None."); 33 } 34 35 _requestProcessor = requestProcessor; 36 } 37 } 38 39 if (requestProcessor != null) 40 { 41 await requestProcessor.ProcessRequestsAsync(httpApplication); 42 } 43 44 await adaptedPipelineTask; 45 await _socketClosedTcs.Task; 46 } 47 ... 48 }
Http1Connection父类HttpProtocol里的ProcessRequests方法会创建一个Context对象,但这还不是最终要找到的HttpContext。

1 private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application) 2 { 3 // Keep-alive is default for HTTP/1.1 and HTTP/2; parsing and errors will change its value 4 _keepAlive = true; 5 6 while (_keepAlive) 7 { 8 ... 9 10 var httpContext = application.CreateContext(this); 11 12 try 13 { 14 KestrelEventSource.Log.RequestStart(this); 15 16 // Run the application code for this request 17 await application.ProcessRequestAsync(httpContext); 18 19 if (_ioCompleted == 0) 20 { 21 VerifyResponseContentLength(); 22 } 23 } 24 ... 25 } 26 }
在HostingApplication类中会看到HttpContext原来是由HttpContextFactory工厂类生成的。

1 public Context CreateContext(IFeatureCollection contextFeatures) 2 { 3 var context = new Context(); 4 var httpContext = _httpContextFactory.Create(contextFeatures); 5 6 _diagnostics.BeginRequest(httpContext, ref context); 7 8 context.HttpContext = httpContext; 9 return context; 10 }
HttpContextFactory类才是最后的一站。

1 public HttpContext Create(IFeatureCollection featureCollection) 2 { 3 if (featureCollection == null) 4 { 5 throw new ArgumentNullException(nameof(featureCollection)); 6 } 7 8 var httpContext = new DefaultHttpContext(featureCollection); 9 if (_httpContextAccessor != null) 10 { 11 _httpContextAccessor.HttpContext = httpContext; 12 } 13 14 var formFeature = new FormFeature(httpContext.Request, _formOptions); 15 featureCollection.Set<IFormFeature>(formFeature); 16 17 return httpContext; 18 }
生成的HttpContext对象最终传递到IHttpApplication的ProcessRequestAsync方法。之后的事情便是WebHost与HostingApplication的工作了。
请求(Request),响应(Response),会话(Session)这些与HTTP接触时最常见到的名词,都出现在HttpContext对象中。说明在处理HTTP请求时,若是需要获取这些相关信息,完全可以通过调用其属性而得到。
通过传递一个上下文环境参数,以协助获取各环节处理过程中所需的信息,在各种框架中是十分常见的作法。ASP.NET Core里的用法并无特别的创新,但其实用性还是毋庸置疑的。如果想要构建自己的框架时,不妨多参考下ASP.NET Core里的代码,毕竟它已是一个较成熟的产品,其中有许多值得借鉴的地方。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构