本篇主题:http://ASP.NET Core进程的启动及核心组件。
启动代码概览
首先使用.NET Core cli 命令 dotnet new web 来创建一个空白的http://ASP.NET Core项目,这里使用的.NET Core版本为2.1.3,http://ASP.NET Core版本是2.1.2。(如果你愿意完全可以从一个空白的cs项目开始开发http://ASP.NET Core应用)
创建好项目后项目目录下有两个代码文件Program.cs和Startup.cs,一个空的wwwroot文件夹以及Properties文件夹和其中的launch.json文件。了解了项目文件后,我们从程序的入口Program.cs文件开始来看看http://asp.net core的启动过程。
Program.cs
public
Startup.cs
public
Program.cs中代码执行了下面4个方法:
- 执行WebHost.CreateDefaultBuilder(args)静态方法,创建IWebHostBuilder对象。
- 执行IWebHostBuilder.UseStartup<Startup>()。
- 执行IWebHostBuilder.Build(),创建一个IWebHost对象。
- 执行IWebHost.Run()。
这就是http://ASP.NET Core启动的全过程,下面简单解读这四个方法的源代码。
CreateDefaultBuilder(args),这个方法new了一个WebHostBuilder对象并读取或设置了一些默认配置,如应用目录,WebServer,应用配置,环境变量,日志对象等。需要说明的是这里的WebHost类是一个静态类并不是实现IWebHost接口的类。
CreateDefaultBuilder(args)方法源代码github.com然后是IWebHostBuilder对象的UseStartup<Startup>()方法,这个方法的逻辑很简单,将Starup类注册到容器中,这个容器非常重要。其中Startup类中包含了配置服务与Middleware的方法,我们会稍后介绍这些内容。
UseStartup<Startup>()方法源代码github.comWebHostBuilder对象的Build()方法,这个方法使用之前的配置构造了new WebHost所需的一系列对象,包括:已创建的服务对象集合,容器对象,配置对象等,然后执行WebHost的初始化方法返回WebHost对象。
WebHostBuilder.Build()方法源代码github.comIWebHost.Run()方法,这个方法是IWebHost的扩展方法,它只有一行代码:
public
这便是http://ASP.NET Core启动过程非常简单的描述,限于篇幅并没有更深入的解读每个方法,有兴趣的读者可以自行查阅源代码。
配置与WebServer
appsettings.json
http://ASP.NET Core已经不使用web.config作为配置文件,默认使用appsettings.json文件,只要你在应用程序根目录中添加该文件,文件内的配置就会被读取。通过Configuration类或者注入IConfiguration对象来访问配置。除了简单的字符串和数值,配置文件也支持POCO对象(plain old CLR object/简单CLR对象,即只包含简单类型属性的类),下面是配置文件内容及配置读取的示例。
配置文件:
{
配置读取代码:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
http://ASP.NET Core支持从下列的位置/方式读取配置:
- Azure Key Vault/Azure键值库
- Command-line arguments/命令行参数
- Custom providers (installed or created)/自定义配置提供程序
- Directory files/目录文件
- Environment variables/环境变量
- In-memory .NET objects/内存中的.NET对象
- Settings files/配置文件
Kestrel&Http.sys
与http://ASP.NET不同,http://ASP.NET Core“内置”了两个WebServer,Kestrel与HTTP.sys,作为进程内的HTTP服务器,其主要功能是监听HTTP请求并将一系列请求功能组成HttpContext提供Web应用使用。
其中Kestrel是一款微软为http://ASP.NET Core开发跨平台的开源Web服务器,Kestrel意为红隼,是一种分布广泛的小型猛禽,飞行快速。寓意该Web服务器小而快的特点。
你可以在部署中单独使用Kestrel或配合一个反向代理服务器,如下图所示。
Http.sys为Windows平台内核功能,实际上IIS的HTTP监听正是运行在Http.sys之上。当你需要在Windows平台上部署但又不使用IIS时你可以使用Http.sys作为WebSever或者需要仅Http.sys支持的功能,如Windows Authentication时也应选择使用Http.sys。不过Kestrel与反向代理服务器的结合可以支持绝大多数WebServer功能,所以推荐使用Kestrel。
两种WebServer对比:
WebServer的配置可以通过Program.cs中BuildWebHost方法中的IWebHostBuilder对象来行进,如下面代码示例(http://ASP.NET Core默认使用Kestrel)。
//使用Http.sys及配置代码
配置选项及具体内容请查阅下面的文档:
Web server implementations in ASP.NET Coredocs.microsoft.com核心概念(Services,Pipeline,Middleware)
重点!重点!重点!
http://ASP.NET Core中有三个核心概念:服务(Services),中间件(Middleware)与请求管道(Request Pipeline),下面先介绍服务。
什么是服务?http://APS.NET Core中的服务就是实现业务逻辑所需的功能组件,之所以称之为服务是因为这些功能组件都放在内置的容器中或者说我们将放在容器中的功能组件称作服务。
什么是容器?http://ASP.NET Core内置一个DI容器(或称为IOC容器),我们通过IWebHost对象的Services属性(IServiceProvider类型)获取服务,通过Startup类中ConfigureServices方法的services参数(IServiceCollection类型)来注册服务,http://ASP.NET Core的大多数功能组件都注册在容器中。该容器由包Microsoft.Extensions.DependencyInjection实现。
Microsoft.Extensions.DependencyInjection源代码github.com为什么需要容器?通过这个容器可以实现依赖注入(DI)/控制反转(IoC)的设计模式,这个模式是http://ASP.NET Core设计的核心。如果不了解依赖注入(Dependency Injection)请另行查阅,下面两个链接提供参考。
Dependency Inversion Principledeviq.com依赖注入的设计模式有下面的优势:
- 通过接口让组件的使用与实现分离,松耦合。
- 管理组件的依赖树,比如一个组件有另外的依赖,这种情况我们会需要不停的new对象。如果使用依赖注入容器我们只需要指定我们需要的组件(比如构造函数注入)容器就会管理好所有的依赖,并且在组件不被需要时释放它。
- 更好的支持单元测试。
- http://ASP.NET Core的容器支持组件的生命周期管理。
我们一步一步来看在这个容器的使用,首先是如何在容器中注册一个服务,这个操作在Startup类的ConfigureServices方法中进行,其中的services参数提供了一系列的注册服务的方法。
public
在注册服务的同时可以配置对象的生命周期,http://ASP.NET Core提供了三种生命周期:
- Transient,每次被使用到时就创建新的实例。
- Scoped,每次请求创建一个实例。
- Singleton,在第一次被用到时创建之后都是用这个实例,也就是单例模式。
需要注意的是不同生命周期服务之间的相互依赖会导致服务生命周期的变化,参考下面的文档。
Dependency injection in ASP.NET Coredocs.microsoft.com服务的使用相对简单的多,仍以Starup类为例,其中的Configure方法就可以使用容器提供的依赖注入,所以你只需要在方法中添加你所需要的类型就可以使用该服务了。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
在实际开发中,我们更多地会在MVC的Controller中使用服务,在Controller中一般使用构造函数注入来使用服务。下面代码所示使用了一个IDateTime的服务。
using
http://ASP.NET Core包含了很多内置服务,如下图所示:
理解并使用好这些服务可以让我们的开发事半功倍,关于服务与容器还有很多细节,更多内容可查看下面的文档。
Dependency injection in ASP.NET Coredocs.microsoft.com下面介绍Pipeline和Middleware,我们知道Web应用的核心是处理HTTP请求,而HTTP请求所经过的“通道”在http://ASP.NET Core中我称之为请求管道即Pipeline,Middleware则是组成这个管道的零件,我们可以把Middleware想象为一节一节的管子,一起拼凑了一个完整的管道。 Middleware的本质是一个处理HttpContext的委托,而委托的“本质”又是方法,所以Middleware就是处理请求的方法,这个方法做两件事情:
- 决定是否执行下一个Middleware。
- 在其后的Middleware被调用前和完成后执行自身的业务逻辑。
我们通过Starup类中Configure方法参数app(IApplicationBuilder类型)的三个方法来对Pipeline进行配置,它们分别是Run,Use,Map。其中Use方法就是为管道注册一个Middleware,而Run方法则是管道的终点,通过它注册的Middleware委托不存在next参数。
public
Map则相当于为特定的请求Url创建一整个管道。
public
Middleware的顺序就是你在Conifg方法中Use,Run,Map的顺序。顺序十分重要,比如在app.Run方法后面注册的Middleware将不会被执行到,还有像处理异常的Middleware应该放在最开始这样它才能够捕获所有Middleware上的异常。
上面解释了Pipleline与Middleware以及在代码层面的体现,现在说说如何在实际开发中开发Middlerware,如果把全部Middlerware都以app.Use的方式来注册的话代码会显得非常冗长也不符合模块化的设计理念,幸好http://ASP.NET Core中已经有标准的Middleware开发流程。
一句话说明标准化的Middleware:将委托封装在一个类中,并以扩展方法的方式提供使用。
下面就是一个“标准”的Middleware,InvokeAsync是它处理请求的方法,而next则在构造函数中注入。
using
这样我们就可以UseMiddleware<RequestCultureMiddleware>()的方式使用这个Middleware了,但是这样还是不够“优雅”,我们需要为IApplicationBuilder添加一个扩展方法UseRequestCulture,代码如下
using
这样我就可以在Startup类中“优雅”的使用我们的Middleware了。
public
关于Middleware有下面几个重点需要了解:
- 生命周期与应用的生命周期相同,也就是Middleware在应用启动的时候被构造并不是在应用收到请求时,而且只生成一次。
- 需要有一个InvokeAsync方法来做为Middleware处理请求的入口,方法需要返回一个Task,你可以在这个方法中添加额外由容器提供服务作为参数。
- 基于工厂的Middleware可以实现生命周期与每次请求相同,限于篇幅详细信息请查看下面的文档:
http://ASP.NET Core也内置了很多Middleware,它们提供的功能可以极大的方便我们的开发。
关于Middleware更多内容请查看下面的官方文档。
ASP.NET Core Middlewaredocs.microsoft.com其他需要知道的
整个http://ASP.NET Core基础包含很多内容,无法在一篇文章中介绍完整,下面是一些个人认为在开发中会用到或者是需要了解的知识点。
环境变量
http://ASP.NET Core会读取系统中环境变量ASPNETCOREENVIRONMENT的值来确定当前的环境,你可以设置任何的值,不过“Development”,“Staging”,“Production”这三个值是由框架支持的,通过env.IsDevelopment(),env.IsDevelopment(),env.IsDevelopment()体现,当然如果你使用其他值的话也可以通过env.IsEnvironment("your_value")方法来判断当前环境是否是“your_value”。
launch.json
这个存在于Properties文件夹的文件用于在开发时对Web应用运行环境进行配置,包括WebServer与环境变量。
StaticFiles
http://ASP.NET Core默认将应用目录下的wwwroot文件夹作为静态文件的根目录,你也可以使用下面代码所示的方式配置自己的静态文件目录。
public
GenericHost
我们之前所使用的都是WebHost,因为我们处理的是HTTP请求,其实http://ASP.NET Core也支持开发非HTTP的Host应用,如消息队列,后台任务等。
除此之外还有一些其他的相对重要的知识点,提供大家作为扩展阅读的参考。
- Routing
- WebSockets
- WebHost启动过程中的异常捕获与处理
- 全球化与本地化
- IHttpClientFactory服务
- http://ASP.NET Core Module
有兴趣的读者也可以前往http://ASP.NET Core官方文档页面深入阅读。
ASP.NET Documentationdocs.microsoft.com总的来说http://ASP.NET Core并不是http://ASP.NET简单复制的开源版本,它经过重新设计,完全支持跨平台,有很强的设计模式痕迹(如依赖注入/DI,仓库模式)并在此基础上实现了很好的模块化与松耦合,以及大量使用异步方法,在扩展性和性能上都有提升,而且它还是开源的!
希望这篇文章能成你学习http://ASP.NET Core的一块敲门砖。有任何疑问或问题欢迎通过评论或私信指出,非常感谢。