跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server。KestrelServer利用一个名为KestrelEngine的网络引擎实现对请求的监听、接收和响应。KetrelServer之所以具有跨平台的特质,源于KestrelEngine是在一个名为libuv的跨平台网络库上开发的。

目录
一、libuv
二、KestrelServer
三、KestrelServerOptions
四、ApplicationLifetime
五、设置监听地址

一、libuv

说起libuv,就不得不谈谈libev,后者是Unix系统上一个事件循环和事件模型的网络库。libev因其具有的高性能成为了继lievent和Event perl module之后一套最受欢迎的网络库。由于Libev不支持Windows,有人在libev之上创建了一个抽象层以屏蔽平台之间的差异,这个抽象层就是libuv。libuv在Windows平台上是采用IOCP的形式实现的,右图揭示了libuv针对Unix和Windows的跨平台实现原理。到目前为止,libuv支持的平台已经不限于Unix和Windows了,包括Linux(2.6)、MacOS和Solaris (121以及之后的版本)在内的平台在libuv支持范围之内。

二、KestrelServer

如下所示的代码片段体现了KestrelServer这个类型的定义。除了实现接口IServer定义的Features属性之外,KestrelServer还具有一个类型为KestrelServerOptions的只读属性Options。这个属性表示对KestrelServer所作的相关设置,我们在调用构造函数时通过输入参数options所代表的IOptions<KestrelServerOptions>对象对这个属性进行初始化。构造函数还具有另两个额外的参数,它们的类型分别是IApplicationLifetime和ILoggerFactory,后者用于创建记录日志的Logger,前者与应用的生命周期管理有关。

   1: public class KestrelServer : IServer

   2: {   

   3:     public IFeatureCollection       Features { get; }

   4:     public KestrelServerOptions     Options { get; }

   5:  

   6:     public KestrelServer(IOptions<KestrelServerOptions> options,IApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory);

   7:     public void Dispose();

   8:     public void Start<TContext>(IHttpApplication<TContext> application);

   9: }

我们一般通过调用WebHostBuilder的扩展方法UseKestrel方法来完成对KestrelServer的注册。如下面的代码片段所示,UseKestrel方法具有两个重载,其中一个具有同一个类型为Action<KestrelServerOptions>的参数,我们可以利用这个参数直接完成对KestrelServerOptions的设置。

   1: public static class WebHostBuilderKestrelExtensions

   2: {

   3:     public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder);

   4:     public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder, Action<KestrelServerOptions> options);

   5: }

三、KestrelServerOptions

由于Server负责请求的监听、接收和响应,所以Server是影响整个Web应用响应能力和吞吐量最大的因素之一,为了更加有效地使用Server,我们往往针对具体的网络负载状况对其作针对性的设置。对于KestrelServer来说,在构造函数中作为参数指定的KestrelServerOptions对象代表针对它所做的设置。我们针对KestrelServer所做的设置主要体现在KestrelServerOptions类型的如下5个属性上。

   1: public class KestrelServerOptions

   2: {   

   3:     //省略其他成员

   4:     public int          MaxPooledHeaders { get; set; }

   5:     public int          MaxPooledStreams { get; set; }

   6:     public bool         NoDelay { get; set; }

   7:     public TimeSpan     ShutdownTimeout { get; set; }

   8:     public int          ThreadCount { get; set; }

   9: }

KestrelServerOptions注册的KetrelServer在管道中会以依赖注入的方式被创建,并采用构造器注入的方式提供其构造函数的参数options,由于这个参数类型为IOptions<KestrelServerOptions>,所以我们利用Options模型以配置的方式来指定KestrelServerOptions对象承载的设置。比如我们可以将KestrelServer的相关配置定义在如下一个JSON文件中。

   1: { 

   2:     "noDelay"         : false, 

   3:     "shutdownTimeout" : "00:00:10", 

   4:     "threadCount"     : 10 

   5: } 

为了让应用加载这么一个配置文件(文件名假设为“KestrelServerOptions.json”),我们只需要在启动类型(Startup)类的ConfigureServces方法中按照如下的方式利用ConfigurationBuilder加载这个配置文件并生成相应的Configuration对象,最后按照Options模型的编程方式完成KestrelServerOptions类型和该对象的映射即可。

   1: public class Startup

   2: {

   3:     //其他成员

   4:     public void ConfigureServices(IServiceCollection services)

   5:     {

   6:         IConfiguration configuration = new ConfigurationBuilder()

   7:             .AddJsonFile("KestrelServerOptions.json")

   8:             .Build();

   9:         services.Configure<KestrelServerOptions>(configuration);

  10:     }

  11: }

四、ApplicationLifetime

我们将所有实现了IApplicationLifetime接口的所有类型及其对应对象统称为ApplicationLifetime。从命名的角度来看,ApplicationLifetime貌似是对当前应用生命周期的描述,而实际上它存在的目的仅仅是在应用启动和关闭(只要是关闭)时对相关组件发送通知而已。如下面的代码片段所示,IApplicationLifetime接口具有三个CancellationToken类型的属性(ApplicationStarted、ApplicationStopping和ApplicationStopped),我们可以利用它们是否已经被取消(Cancel)确定当前应用的状态(已经开启、正在关闭和已经关闭)。如果试图关闭应用,StopApplication方法应该被调用以发出应用正在被关闭的通知。对于KestrelServer来说,如果请求处理线程中发生未被处理异常,它会调用这个方法。

   1: public interface IApplicationLifetime

   2: {

   3:     CancellationToken ApplicationStarted { get; }

   4:     CancellationToken ApplicationStopping { get; }

   5:     CancellationToken ApplicationStopped { get; }

   6:  

   7:     void StopApplication();

   8: }

ASP.NET Core默认使用的ApplicationLifetime是具有如下定义的一个同名类型。可以看出它实现的三个属性返回的CancellationToken对象是通过三个对应的CancellationTokenSource生成。除了实现IApplicationLifetime接口的StopApplication方法用于发送“正在关闭”通知之外,这个类型还定义了额外两个方法(NotifyStarted和NotifyStopped)用于发送“已经开启/关闭”的通知。

   1: public class ApplicationLifetime : IApplicationLifetime

   2: {

   3:     private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();

   4:     private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();

   5:     private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();    

   6:  

   7:     public CancellationToken ApplicationStarted

   8:     {

   9:         get { return this._startedSource.Token; }

  10:     }

  11:     public CancellationToken ApplicationStopped

  12:     {

  13:         get { return this._stoppedSource.Token; }

  14:     }

  15:     public CancellationToken ApplicationStopping

  16:     {

  17:         get { return this._stoppingSource.Token; }

  18: }

  19:  

  20:     public void NotifyStarted()

  21:     {

  22:         this._startedSource.Cancel(false);

  23:     }

  24:     public void NotifyStopped()

  25:     {

  26:         this._stoppedSource.Cancel(false);

  27:     }

  28:     public void StopApplication()

  29:     {

  30:         this._stoppingSource.Cancel(false);

  31:     }

  32: }

一个ASP.NET Core应用利用管道处理请求,所以管道的生命周期等同于应用自身的生命周期。当我们调用Run方法开启WebHost时,请求处理管道被构建出来。如果管道在处理请求时发生未被处理的异常,管道的Sever会调用ApplicationLifeTime对象的StopApplication方法向WebHost发送关闭应用的通知以便后者执行一些回收释放工作。

五、设置监听地址

在演示的实例中,我们实际上并不曾为注册的KestrelServer指定一个监听地址,从运行的效果我们不难看出,WebHost在这种情况下会指定“http://localhost:5000”为默认的监听地址,Server的监听地址自然可以显式指定。在介绍如何通过编程的方式为Server指定监听地址之前,我们有先来认识一个名为ServerAddressesFeature的特性。

我们知道表示Server的接口IServer中定义了一个类型为IFeatureCollection 的只读属性Features,它表示用于描述当前Server的特性集合,ServerAddressesFeature作为一个重要的特性,就包含在这个集合之中。我们所说的ServerAddressesFeature对象是对所有实现了IServerAddressesFeature接口的所有类型及其对应对象的统称,该接口具有一个唯一的只读属性返回Server的监听地址列表。ASP.NET Core默认使用的ServerAddressesFeature是具有如下定义的同名类型。

   1: public interface IServerAddressesFeature

   2: {

   3:     ICollection<string> Addresses { get; }

   4: }

   5:  

   6: public class ServerAddressesFeature : IServerAddressesFeature

   7: {

   8:     public ICollection<string> Addresses { get; }

   9: }

对于WebHost在通过依赖注入的方式创建的Server,由它的Features属性表示的特性集合中会默认包含这么一个ServerAddressesFeature对象。如果没有一个合法的监听地址被添加到这个 ServerAddressesFeature对象的地址列表中,WebHost会将显式指定的地址(一个或者多个)添加到该列表中。我们显式指定的监听地址实际上是作为WebHost的配置保存在一个Configuration对象上,配置项对应的Key为“server.urls”,WebHostDefaults的静态只读属性ServerUrlsKey返回的就是这么一个Key。

   1: new WebHostBuilder()

   2:     .UseSetting(WebHostDefaults.ServerUrlsKey, "http://localhost:3721/")

   3:     .UseMyKestrel()

   4:     .UseStartup<Startup>()

   5:     .Build()

   6:      .Run();

WebHost的配置最初来源于创建它的WebHostBuilder,后者提供了一个UseSettings方法来设置某个配置项的值,所以我们可以采用如下的方式来指定监听地址(“http://localhost:3721/”)。不过,针对监听地址的显式设置,最直接的编程方式还是调用WebHostBuilder的扩展方法UseUrls,如下面的代码片段所示,该方法的实现逻辑与上面完全一致。

   1: public static class WebHostBuilderExtensions

   2: {

   3:     public static IWebHostBuilder UseUrls(this IWebHostBuilder hostBuilder, params string[] urls) 

   4:     =>hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, string.Join(ServerUrlsSeparator, urls)) ;    

   5: }

聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer的更多相关文章

  1. 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs

    原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...

  2. 聊聊asp.net core 授权流程

    在上一篇 聊聊 asp.net core 认证和授权 中我们提到了认证和授权的基本概念,以及认证和授权的关系及他们之间的协同工作流程,在这篇文章中,我将通过分析asp.net core 3.1 授权流 ...

  3. 从零搭建一个IdentityServer——聊聊Asp.net core中的身份验证与授权

    OpenIDConnect是一个身份验证服务,而Oauth2.0是一个授权框架,在前面几篇文章里通过IdentityServer4实现了基于Oauth2.0的客户端证书(Client_Credenti ...

  4. ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客

    原文:ASP.NET Core默认注入方式下如何注入多个实现(多种方式) - sky 胡萝卜星星 - CSDN博客 版权声明:本文为starfd原创文章,转载请标明出处. https://blog.c ...

  5. ASP.NET Core默认容器实现Controller的属性注入

    仅针对Controller的属性注入: 使用默认容器,不依赖第三方库: 故事背景   闲来无事给项目做优化,发现大多数Controller里面都会用到Logger和AutoMapper,每个Contr ...

  6. ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  7. ASP.NET Core环境并运行 继续跨平台

    ASP.NET Core环境并运行 继续跨平台 无需安装mono,在Linux(Ubuntu)下搭建ASP.NET Core环境 继续.NET跨平台 上一篇:使用VS Code开发ASP.NET Co ...

  8. ASP.NET Core 2.0发布/部署到Ubuntu服务器并配置Nginx反向代理

    原文链接https://www.linuxidc.com/Linux/2017-12/149557.htm ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用AS ...

  9. 聊聊 asp.net core 认证和授权

    使用asp.net core 开发应用系统过程中,基本上都会涉及到用户身份的认证,及授权访问控制,因此了解认证和授权流程也相当重要,下面通过分析asp.net core 框架中的认证和授权的源码来分析 ...

随机推荐

  1. TypeScript: Angular 2 的秘密武器(译)

    本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...

  2. 【探索】利用 canvas 实现数据压缩

    前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...

  3. 微信小程序体验(2):驴妈妈景区门票即买即游

    驴妈妈因为出色的运营能力,被腾讯选为首批小程序内测单位.驴妈妈的技术开发团队在很短的时间内完成了开发任务,并积极参与到张小龙团队的内测问题反馈.驴妈妈认为,移动互联网时代,微信是巨大的流量入口,也是旅 ...

  4. 让kindeditor显示高亮代码

    kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: ...

  5. Android业务组件化之URL Scheme使用

    前言: 最近公司业务发展迅速,单一的项目工程不再适合公司发展需要,所以开始推进公司APP业务组件化,很荣幸自己能够牵头做这件事,经过研究实现组件化的通信方案通过URL Scheme,所以想着现在还是在 ...

  6. FragmentTabHost的基本用法

    开通博客以来已经约莫1个月了.几次想提笔写写东西,但总是由于各种各样的原因并没有开始.现在,年假刚结束,项目也还没有开始,但最终促使我写这篇博客的是,看了一篇博友写的新年计划,说是要在新的一年中写50 ...

  7. input标签中button在iPhone中圆角的问题

    1.问题 使用H5编写微信页面时,使用<input type="button"/>时,在Android手机中显示正常,但是在iPhone手机中则显示不正常,显示为圆角样 ...

  8. 利用注册表在右键添加VS15的快捷方式打开文件夹

    1.简介 最近安装VS15 Preview 5,本版本可以打开"文件夹" 是否可以向Visual Studio Code一样在文件夹或文件右键菜单添加"Open with ...

  9. 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)

    坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ...

  10. .NET同步与异步之相关背景知识(六)

    在之前的五篇随笔中,已经介绍了.NET 类库中实现并行的常见方式及其基本用法,当然.这些基本用法远远不能覆盖所有,也只能作为一个引子出现在这里.以下是前五篇随笔的目录: .NET 同步与异步之封装成T ...