写一个简版 asp.net core
摘要:在上面的 IServer 定义里有一个 requestHandler 的 对象,在 asp.net core 里是一个名称为 RequestDelegate 的对象,而用来构建这个委托的在 asp.net core 里是 IApplicationBuilder ,这些在蒋老师和 Edison 的文章和代码里都可以看到,这里我们只是简单介绍下,我在 MiniAspNetCore 的示例中没有使用这些对象,而是使用了自己抽象的 PipelineBuilder 和原始委托实现的。asp.net core 里 RequestDelegate 定义:。
动手写一个简版 asp.net core
Intro
之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 asp.net core 的理解 ,最近自己写了一个 MiniAspNetCore ,写篇文章总结一下。
HttpContext
HttpContext
可能是最为常用的一个类了, HttpContext
是请求上下文,包含了所有的请求信息以及响应信息,以及一些自定义的用于在不同中间件中传输数据的信息
来看一下 HttpContext
的定义:
HttpRequest
即为请求信息对象,包含了所有请求相关的信息,
HttpResponse
为响应信息对象,包含了请求对应的响应信息
RequestServices
为 asp.net core 里的 RequestServices
,代表当前请求的服务提供者,可以使用它来获取具体的服务实例
Features
为 asp.net core 里引入的对象,可以用来在不同中间件中传递信息和用来解耦合
,下面我们就来看下 HttpRequest
和 HttpResponse
是怎么实现的
HttpRequest:
HttpResponse:
Features
上面我们提供我们可以使用 Features
在不同中间件中传递信息和解耦合
由上面 HttpRequest
/ HttpResponse
的代码我们可以看出来, HttpRequest
和 HttpResponse
其实就是在 IRequestFeature
和 IResponseFeature
的基础上封装了一层,真正的核心其实是 IRequestFeature
/ IResponseFeature
,而这里使用接口就很好的实现了解耦,可以根据不同的 WebServer 使用不同的 RequestFeature
/ ResponseFeature
,来看下 IRequestFeature
/ IResponseFeature
的实现
这里的实现和 asp.net core 的实际的实现方式应该不同,asp.net core 里 Headers 同一个 Header 允许有多个值,asp.net core 里是 StringValues 来实现的,这里简单处理了,使用了一个 NameValueCollection
对象
上面提到的 Features
是一个 IFeatureCollection
对象,相当于是一系列的 Feature
对象组成的,来看下 FeatureCollection
的定义:
这里 IFeatureCollection
直接实现 IDictionary<Type,object>
,通过一个字典 Feature 类型为 Key,Feature 对象为 Value 的字典来保存
为了方便使用,可以定义两个扩展方法来方便的Get/Set
Web服务器
上面我们已经提到了 Web 服务器通过 IRequestFeature
/ IResponseFeature
来实现不同 web 服务器和应用程序的解耦,web 服务器只需要提供自己的 RequestFeature
/ ResponseFeature
即可
为了抽象不同的 Web 服务器,我们需要定义一个 IServer
的抽象接口,定义如下:
IServer
定义了一个 StartAsync
方法,用来启动 Web服务器,
StartAsync
方法有两个参数,一个是 requestHandler,是一个用来处理请求的委托,另一个是取消令牌用来停止 web 服务器
示例使用了 HttpListener
来实现了一个简单 Web 服务器, HttpListenerServer
定义如下:
HttpListenerServer
实现的 RequestFeature
/ ResponseFeatue
为了方便使用,为 HttpListenerContext
定义了两个扩展方法,就是上面 HttpListenerServer
中的 GetRequestFeature
/ GetResponseFeature
:
RequestDelegate
在上面的 IServer
定义里有一个 requestHandler 的 对象,在 asp.net core 里是一个名称为 RequestDelegate
的对象,而用来构建这个委托的在 asp.net core 里是 IApplicationBuilder
,这些在蒋老师和 Edison 的文章和代码里都可以看到,这里我们只是简单介绍下,我在 MiniAspNetCore 的示例中没有使用这些对象,而是使用了自己抽象的 PipelineBuilder
和原始委托实现的
asp.net core 里 RequestDelegate
定义:
其实和我们上面定义用的 Func<HttpContext,Task>
是等价的
IApplicationBuilder
定义:
我们这里没有定义 IApplicationBuilder
,使用了简化抽象的 IAsyncPipelineBuilder
,定义如下:
对于 asp.net core 的中间件来说 ,上面的 TContext
就是 HttpContext
,替换之后也就是下面这样的:
是不是和 IApplicationBuilder
很像,如果不像可以进一步把 Func<HttpContext,Task>
使用 RequestDelegate
替换
最后再将接口名称替换一下:
至此,就完全可以看出来了,这 IAsyncPipelineBuilder<HttpContext>
就是一个简版的 IApplicationBuilder
IAsyncPipelineBuilder
和 IApplicationBuilder
的作用是将注册的多个中间件构建成一个请求处理的委托
中间件处理流程:
更多关于 PipelineBuilder 构建中间件的信息可以查看 让 .NET 轻松构建中间件模式代码 了解更多
WebHost
通过除了 Web 服务器之外,还有一个 Web Host 的概念,可以简单的这样理解,一个 Web 服务器上可以有多个 Web Host,就像 IIS/nginx (Web Server) 可以 host 多个站点
可以说 WebHost 离我们的应用更近,所以我们还需要 IHost
来托管应用
WebHost
定义:
为了方便的构建 Host
对象,引入了 HostBuilder
来方便的构建一个 Host
,定义如下:
WebHostBuilder
:
这里的示例我在 IHostBuilder
里增加了一个 Initialize
的方法来做一些初始化的操作,我觉得有些数据初始化配置初始化等操作应该在这里操作,而不应该在 Startup
的 Configure
方法里处理,这样 Configure
方法可以更纯粹一些,只配置 asp.net core 的请求管道,这纯属个人意见,没有对错之分
这里 Host 的实现和 asp.net core 的实现不同,有需要的可以深究源码,在 asp.net core 2.x 的版本里是有一个 IWebHost
的,在 asp.net core 3.x 以及 .net 5 里是没有 IWebHost
的取而代之的是通用主机 IHost
, 通过实现了一个 IHostedService
来实现 WebHost
的
Run
运行示例代码:
在示例项目目录下执行 dotnet run
,并访问 http://localhost:5100/
:
仔细观察浏览器 console
或 network
的话,会发现还有一个请求,浏览器会默认请求 /favicon.ico
获取网站的图标
因为我们针对这个请求没有任何中间件的处理,所以直接返回了 404
在访问 /test
,可以看到和刚才的输出完全不同,因为这个请求走了另外一个分支,相当于 asp.net core 里 Map
/ MapWhen
的效果,另外 Run
代表里中间件的中断,不会执行后续的中间件
More
上面的实现只是我在尝试写一个简版的 asp.net core 框架时的实现,和 asp.net core 的实现并不完全一样,如果需要请参考源码,上面的实现仅供参考,上面实现的源码可以在 Github 上获取 https://github.com/WeihanLi/SamplesInPractice/tree/master/MiniAspNetCore
asp.net core 源码:https://github.com/dotnet/aspnetcore
Reference
-
https://www.cnblogs.com/artech/p/inside-asp-net-core-framework.html
-
https://www.cnblogs.com/artech/p/mini-asp-net-core-3x.html
-
https://www.cnblogs.com/edisonchou/p/aspnet_core_mini_implemention_introduction.html
-
https://github.com/WeihanLi/SamplesInPractice/tree/master/MiniAspNetCore