当KestrelServer启动时,会绑定相应的IP地址,同时在绑定时将加入HttpConnectionMiddleware作为终端连接的中间件。

 public async Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
{
try
{
... async Task OnBind(ListenOptions endpoint)
{
// Add the HTTP middleware as the terminal connection middleware
endpoint.UseHttpServer(endpoint.ConnectionAdapters, ServiceContext, application, endpoint.Protocols); var connectionDelegate = endpoint.Build(); // Add the connection limit middleware
if (Options.Limits.MaxConcurrentConnections.HasValue)
{
connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync;
} var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate);
var transport = _transportFactory.Create(endpoint, connectionDispatcher);
_transports.Add(transport); await transport.BindAsync().ConfigureAwait(false);
} await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false);
} ...
}
 public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols)
{
var middleware = new HttpConnectionMiddleware<TContext>(adapters, serviceContext, application, protocols);
return builder.Use(next =>
{
return middleware.OnConnectionAsync;
});
}

当请求抵达此中间件时,在其OnConnectionAsync方法里会创建HttpConnection对象,并通过该对象处理请求

 public async Task OnConnectionAsync(ConnectionContext connectionContext)
{
... var connection = new HttpConnection(httpConnectionContext);
_serviceContext.ConnectionManager.AddConnection(httpConnectionId, connection); try
{
var processingTask = connection.ProcessRequestsAsync(_application); ...
}
...
}

ProcessRequestsAsync方法内部会根据HTTP协议的不同创建Http1Connection或者Http2Connection对象,一般为Http1Connection。

 public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication)
{
try
{
... lock (_protocolSelectionLock)
{
// Ensure that the connection hasn't already been stopped.
if (_protocolSelectionState == ProtocolSelectionState.Initializing)
{
switch (SelectProtocol())
{
case HttpProtocols.Http1:
// _http1Connection must be initialized before adding the connection to the connection manager
requestProcessor = _http1Connection = CreateHttp1Connection(_adaptedTransport, application);
_protocolSelectionState = ProtocolSelectionState.Selected;
break;
case HttpProtocols.Http2:
// _http2Connection must be initialized before yielding control to the transport thread,
// to prevent a race condition where _http2Connection.Abort() is called just as
// _http2Connection is about to be initialized.
requestProcessor = CreateHttp2Connection(_adaptedTransport, application);
_protocolSelectionState = ProtocolSelectionState.Selected;
break;
case HttpProtocols.None:
// An error was already logged in SelectProtocol(), but we should close the connection.
Abort(ex: null);
break;
default:
// SelectProtocol() only returns Http1, Http2 or None.
throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
} _requestProcessor = requestProcessor;
}
} if (requestProcessor != null)
{
await requestProcessor.ProcessRequestsAsync(httpApplication);
} await adaptedPipelineTask;
await _socketClosedTcs.Task;
}
...
}

Http1Connection父类HttpProtocol里的ProcessRequests方法会创建一个Context对象,但这还不是最终要找到的HttpContext。

 private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application)
{
// Keep-alive is default for HTTP/1.1 and HTTP/2; parsing and errors will change its value
_keepAlive = true; while (_keepAlive)
{
... var httpContext = application.CreateContext(this); try
{
KestrelEventSource.Log.RequestStart(this); // Run the application code for this request
await application.ProcessRequestAsync(httpContext); if (_ioCompleted == )
{
VerifyResponseContentLength();
}
}
...
}
}

在HostingApplication类中会看到HttpContext原来是由HttpContextFactory工厂类生成的。

 public Context CreateContext(IFeatureCollection contextFeatures)
{
var context = new Context();
var httpContext = _httpContextFactory.Create(contextFeatures); _diagnostics.BeginRequest(httpContext, ref context); context.HttpContext = httpContext;
return context;
}

HttpContextFactory类才是最后的一站。

 public HttpContext Create(IFeatureCollection featureCollection)
{
if (featureCollection == null)
{
throw new ArgumentNullException(nameof(featureCollection));
} var httpContext = new DefaultHttpContext(featureCollection);
if (_httpContextAccessor != null)
{
_httpContextAccessor.HttpContext = httpContext;
} var formFeature = new FormFeature(httpContext.Request, _formOptions);
featureCollection.Set<IFormFeature>(formFeature); return httpContext;
}

生成的HttpContext对象最终传递到IHttpApplication的ProcessRequestAsync方法。之后的事情便是WebHost与HostingApplication的工作了。

请求(Request),响应(Response),会话(Session)这些与HTTP接触时最常见到的名词,都出现在HttpContext对象中。说明在处理HTTP请求时,若是需要获取这些相关信息,完全可以通过调用其属性而得到。

通过传递一个上下文环境参数,以协助获取各环节处理过程中所需的信息,在各种框架中是十分常见的作法。ASP.NET Core里的用法并无特别的创新,但其实用性还是毋庸置疑的。如果想要构建自己的框架时,不妨多参考下ASP.NET Core里的代码,毕竟它已是一个较成熟的产品,其中有许多值得借鉴的地方。

DotNetCore深入了解之二HttpContext类的更多相关文章

  1. UML学习(二)-----类图

    UML学习(二)-----类图 http://www.cnblogs.com/silent2012/archive/2011/09/07/2169946.html http://www.cnblogs ...

  2. c/c++ 模板与STL小例子系列<二> 模板类与友元函数

    c/c++ 模板与STL小例子系列 模板类与友元函数 比如某个类是个模板类D,有个需求是需要重载D的operator<<函数,这时就需要用到友元. 实现这样的友元需要3个必要步骤 1,在模 ...

  3. Java笔记(二)类

    类 一.类的基础 1.类---一种自定义数据类型. 2.与方法内创建局部变量不同,在创建对象的时候,所有的实例变量都会分配 一个默认值,这与创建数组的时候是类似的. 3.在{}对实例变量内赋值: in ...

  4. Spring Developer Tools 源码分析:二、类路径监控

    在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...

  5. JavaSE-基础语法(二)-系统类(java.lang.*)和工具类(java.util.*)

    系统类(java.lang.*)和工具类(java.util.*) 一.系统类(java.lang.*) 这个包下包含java语言的核心类,如String.Math.System和Thread类等,使 ...

  6. Lua面向对象之二:类继承

    1.类继承 ①代码 Sharp = { } --① 父类 function Sharp:new() local new_sharp = { } self.__index = self --②,self ...

  7. Kendo UI 单页面应用(二) Router 类

    Kendo UI 单页面应用(二) Router 类 Route 类负责跟踪应用的当前状态和支持在应用的不同状态之间切换.Route 通过 Url 的片段功能(#url)和流量器的浏览历史功能融合在一 ...

  8. (3)一般处理程序 ,HttpContext类

    一般处理程序的后缀名 .ashx  ,专门用来处理web请求 新建后默认代码: public class Handler1 : IHttpHandler { public void ProcessRe ...

  9. java 基础二 Graphics类

    一.处理图形 1.画直线 void drawLine (int startx , int starty , int endx , int endy) 参数列表:直线开始的横坐标.纵坐标,直线结束的横坐 ...

随机推荐

  1. Koa源码分析(一) -- generator

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: 1. Koa源码分析(一) -- generator 2. Koa源码分析(二) -- co的实现 ...

  2. php中的问题整理

    1.什么是 CSRF 攻击 ?XSS 攻击?如何防范? CSRF,跨站请求伪造,攻击方伪装用户身份发送请求从而窃取信息或者破坏系统.讲述基本原理:用户访问A网站登陆并生成了cookie,再访问B网站, ...

  3. sqlserver存储过程分页记录

    USE [HK_ERP]GO/****** Object: StoredProcedure [dbo].[GetPageBillsByShopID] Script Date: 2018/10/30 1 ...

  4. IOS 获取系统相册和拍照使用HXPhotoPicker 返回页面时页面上移被nav遮住问题

    解决: - (void)viewWillAppear:(BOOL)animated{    [super viewWillAppear:animated]; self.automaticallyAdj ...

  5. 2019.03.09 codeforces833B. The Bakery(线段树优化dp)

    传送门 线段树优化dpdpdp入门题. 要求把nnn个数分成kkk段,每段价值为里面不相同的数的个数,求所有段的价值之和最大值.n≤35000,k≤50n\le35000,k\le50n≤35000, ...

  6. C#如何以管理员身份运行程序 转

    在使用winform程序获取调用cmd命令提示符时,如果是win7以上的操作系统,会需要必须以管理员身份运行才会执行成功,否则无效果或提示错误. 比如在通过winform程序执行cmd命令时,某些情况 ...

  7. mysql 循环写入数据库

    测试过程经常用到插入数据 我们首先建一个函数: delimiter # create procedure test_double() begin declare i int default 0; de ...

  8. github install

    1.安装git依赖包 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUti ...

  9. C#使用Dotfuscator混淆代码的加密方法

    C#编写的代码如果不进行一定程度的混淆和加密,那么是非常容易被反编译进行破解的,特别是对于一些商业用途的C#软件来说,因为盯着的人多,更是极易被攻破.使用VS自带的Dotfuscator可以实现混淆代 ...

  10. 安装easygui

    1.下载0.96的easygui 官网: http://easygui.sourceforge.net/ 2.解压后得到文件夹,里面有两个文件分别为,setup.py和easygui.py 3.在py ...