在本文中,我们将设计一些复杂的概念,因为我们应该分析ASP.NET核心的启动和操作原理,配置文件的加载过程,并解释依赖注入和控制反转的概念。
俗话说,授人以鱼不如授人以渔,所以本文旨在带你分析一下源代码,这样你就能知道为什么了。要偷懒,继续用前一篇文章的例子!
1.首先是上一篇文章的项目结构,如下图所示。熟悉C#的朋友应该知道,如果想找一个程序入库,应该找Main方法。ASP.NET核心的主要方法在Program.cs文件中。
2.打开后,我看到了下面的代码。我加了评论。大家都会看的。让我们一步一步来分析
///summary ///Main方法,程序的入口方法////summary////param name=' args '/param public static void Main(string[]args){ createwebhostbuilder(args)//调用以下方法。返回一个IWebHostBuilder对象。Build()//创建一个IWebHost。使用上面返回的IWebHostBuilder对象运行();//运行上面创建的IWebHost对象来运行我们的Web应用程序,换句话说,启动一个一直监听http请求的任务} public static iwebhostbuilder createwebhostbuilder(string[]args)=Web host。createdefaultbuilder(args)//初始化一个新的IWebHostBuilder实例。带有默认配置信息的UseStartupStartup();//为网络主机指定启动类。3.你可以看到ASP.NET核心程序实际上是一个控制台程序,运行一个webhost对象来启动一个监听http请求的运行任务。因此,我们的重点是分析创建该网络主机的过程:
创建IWebHostBuilder->创建IWebHost->然后运行创建的IWebHost。
4.这里我们分析在IWebHostBuilder的构建下的创建过程。感兴趣的朋友可以阅读,不感兴趣的朋友可以跳到下一步继续阅读。
1.首先,从https://github.com/aspnet/AspNetCore/tree/release/2.1,的github开源地址aspnetcore下载源代码(我们使用2.1)。然后使用vscode打开解压缩的文件夹。至于vscode如何加载文件,你可以阅读我关于开发的文章。NET核心与Visual Studio代码。
2.根据IWebHostBuilder的命名空间,我们找到了它的实现,路径是src/hosting/hosting/src/webhostbuilder . cs。
3.通过上面的代码,我们可以看到第一步是通过BuildCommonServices构建一个ServiceCollection。为什么这么说?让我们先跳到BuidCommonServices方法。
可以看到,var services=newservice collection();首先,新建一个ServiceCollection,然后将大量内容注入到服务中,比如:WebHostOptions、IHostingEnvironment、IHttpContextFactory、MiddlewareFactory等。(其实依赖注入的概念在这里已经设计好了,先考虑一下),以后再用吧!最后,BuildCommonServices返回服务对象。
4.上面的依赖注入中有一个方法。不知道大家有没有注意到,因为在第2步发布的代码中有一个UseStartupStartup()。事实上,在上面的BuildCommonServices方法中还注入了IStartup。首先,判断Startup类是否继承自IStartup接口。如果它继承了,它可以直接添加到服务中。如果不是,它需要通过ConventionBasedStartup(方法)将方法转换为IStartUp,并将其注入到服务中。结合我们上面的代码,似乎我们通常使用后一种注入方法。
5.我们返回到构建方法,获取由BuildCommonServices方法构建的ServiceCollection实例,然后通过GetProviderFromfactory(托管服务)方法构建IServiceProvider对象。到目前为止,IServiceCollection和IServiceProvider都已经得到了。然后,根据IServiceCollection和IServiceProvider对象,构造WebHost对象。构造的网络主机实例不能直接返回,需要通过初始化来初始化网络主机实例。让我们看看初始化函数Initialize做了什么。
6.在这里,我们将代码导航到src/hosting/hosting/src/internal/web host . cs以找到Initialize方法。如下图所示,主要是EnsureApplicationServices方法。
7.我们继续按照如下方式导航和检查该方法的内容:获取Startup对象,然后将该对象注入到_applicationServiceCollection中。
8.到目前为止,在我们的构建中注册的对象和在StartUp中注册的对象已经被添加到依赖注入容器中,下一步是运行。此运行的代码在src hosting hosting src webhostextensions . cs中。代码如下:
WebHost执行RunAsync来运行web应用程序,并返回一个只有在令牌被触发或关闭时才能完成的任务(下面是异步编程的知识,我们将在后面详细解释)。这是我们运行ASP.Net核心程序时看到的命令行窗口。不关窗,不按Ctrl C,就完不成。
9.到目前为止开始的过程的源代码分析已经完成。
4.打开我们在上一篇文章中创建的项目,并在appsettings.json中添加以下内容:
{ ' Logging ' : { ' LogLevel ' : { ' Default ' : ' Warning ' } },' Content': { 'Id': 1,' title': 'title1 ',' content': 'content1 ',Status' : 1,' Add _ Time ' : ' 2018-11-21 16:29 ',' Modify _ Time ' :然后在启动类的配置服务中注册TOptions对象,如下所示
服务。配置内容(配置。GetSection(' Content ');//注册TOption实例对象
这段代码匹配appsettings.json配置文件中“内容”节点的Content对象。
6.修改内容控制器的控制器代码如下:
私有只读内容内容;public content controller(ioptioncontent选项){ contents=option。价值;}///summary////第一页显示/////summary//returns/returns public interaction result index(){ return view(新内容视图模型{contents=新列表内容{ contents } });}7.按F5运行,然后导航到Content目录,看到如下页面:显示内容已经从appsettings.json文件成功加载。这一切是怎么发生的?我们一步一步来分析。
8.回顾我们的Main方法,我们发现有一个CreateDefaultBuilder方法,它为我们做了一些默认设置,然后加载我们的配置文件!
9.我们在源代码中找到了CreateDefaultBuilder的源代码(反正我搜索了很久,一开始是在Hosting下,实际是在MetaPackages下),位于src MetaPackages src Microsoft。aspnetcore webhost.cs,但有些人可能找不到。可以看到这个方法会在ConfigureAppConfiguration的时候默认加载appsettings文件,并做一些初始设置,这样我们就可以不用任何操作加载appsettings的内容了。
10.既然我们知道了原理,让我们试着重写这个ConfigureAppConfiguration,然后加载我们的自定义json文件。
11.右键单击创建一个新的Content.json文件,然后输入以下内容:
{ 'ContentList': { 'Id': 1,' title': 'title1来自diy json ',' content': 'content1来自diy json ',' status': 1,Add _ time ' : ' 2018-11-21 16:29 ',' modify _ time' : null}} 12。然后根据下面的代码打开Program.cs:
///summary ///Main方法,程序的入口方法////summary////param name=' args '/param public static void Main(string[]args){ createwebhostbuilder(args)//调用以下方法。返回一个WebHostBuilder对象。Build()//创建一个网络主机。使用上面返回的WebHostBuilder对象运行();//运行上面创建的WebHost对象来运行我们的Web应用程序,换句话说,启动一个一直监听http请求的任务} public static iwebhostbuilder createwebhostbuilder(string[]args)=Web host。createdefaultbuilder(args)//用默认配置信息初始化一个新的IWebHostBuilder实例。configureappconfiguration((hosting context,config)={varenv=hostingcontext。宿主环境;配置。AddJsonFile('appsettings.json ',optional: true,reloadOnChange: true)。AddJsonFile($'appsettings。{env。环境名称}。json ',optional:为真,reloadOnChange:为真)。AddJsonFile('Content.json ',optional:false,reloadOnChange:false)。AddEnvironmentVariables();}) .UseStartupStartup();//为网络主机指定了启动类
13.那么启动时配置服务中的代码修改如下:
14.然后按F5运行代码。如下图所示,数据是从我们新添加的json文件中加载的。
15.让我们在这里谈更多。如果传统ASP.NET的web.config文件被更改,必须重新启动站点才能使配置文件生效。但是ASP.NET芯的配置文件支持热更新,无需重启网站即可加载更新,只需设置属性即可,如下图所示:
16.配置文件的源代码解释在这里。下面开始依靠注射的解释。
依赖注入:当一个对象ContentController需要另一个对象Content来协同完成任务时,这个ContentController就和这个Content对象有依赖关系。那么在这个ContentController中,它是如何注入的呢?是从控制器注入的,如下图所示:
你从ASP.NET转学的时候,以前有没有想过同样的新对象?我没有一个对象是新的(要是我女朋友能是新的就好了……),当然,除了一个单一的对象,是静态的。
这里设计的另一个概念是控制反转。
那么什么是控制反转呢?你有没有看到上面你自己的新对象只是一个向前的旋转,因为你创建了你想要使用的对象。那么这种新对象就不需要你自己的了,而是直接进来的,也就是控制反转。(不知道这个比喻是否恰到好处。)
你已经知道依赖注入和控制反转了吗?喜欢思考的朋友可能会问,这个构造函数中的IOptionsContent选项是怎么出来的?这里将介绍容器的概念。
什么是容器?
在这里,对象IOptionsContent选项被创建为一个容器。还记得我们分析上面的源代码时,许多东西被注入到IServiceCollection中吗?实际上,它是将方法注入到容器IServiceCollection中,以便在其他地方使用时可以自动注入。
这是容器的优势,它以统一的方式管理实例的创建和销毁。你只需要关心如何使用它,不需要知道如何创建和销毁它。
当然,容器创建的所有实例都有一个生命周期。以下列举,但不做过多解释。
Transient:每次访问都会创建一个新的实例Scoped:在同一个Scope中只初始化一个实例,可以理解为(每个请求级别只创建一个实例,同一个http请求在同一个作用域中)Singleton:在整个应用程序生命周期内只创建一个实例也很简单,下节课我会通过例子详细讲解!因为现在的例子还没有演示。