05、NetCore2.0依赖注入(DI)之Web应用启动流程管理
05、NetCore2.0依赖注入(DI)之Web应用启动流程管理
在一个Asp.net core 2.0 Web应用程序中,启动过程都做了些什么?NetCore2.0的依赖注入(DI)框架是如何管理启动过程的?WebServer和Startup是如何注册的?
------------------------------------------------------------------------------------------------------------
写在前面:这是一个系列的文章,总目录请移步:NetCore2.0技术文章目录
------------------------------------------------------------------------------------------------------------
一、我们先看看依赖注入框架是如何使用的
NetCore2.0的依赖注入(DI)框架是要解决对象创建的问题,把创建对象与使用对象进行解耦。调用者不需要关心对象是单例的还是多实例的;服务的扩展和调用也更容易。
首先使用VS2017新建一个控制台程序,要使用依赖注入(DI)框架,我们需要引入微软的依赖注入包:
install-package Microsoft.Extensions.DependencyInjection
我们声明一个自己的接口,并实现一个类
// 接口
interface IRun
{
void Run();
} // 实现类
class Run : IRun
{
void IRun.Run()
{
Console.WriteLine("跑起来,兄弟");
}
}
使用DI框架来注册接口和类的实例;并通过服务提供者来访问接口
using Microsoft.Extensions.DependencyInjection;
using System; namespace MyServiceBus
{
class Program
{
static void Main(string[] args)
{
// 实例化DI框架
IServiceCollection services = new ServiceCollection();
// 在DI框架中加入接口的一个实例(它是单例的)
services.AddSingleton<IRun, Run>(); // 服务的提供者
IServiceProvider serviceProvider = services.BuildServiceProvider(); // ============上下两部分代码一般不会同时出现在一个类中======== // 从服务提供者获取接口的实例(不用关心是如何创建的)
serviceProvider.GetService<IRun>().Run();
Console.ReadLine();
}
}
}
看看运行效果吧!可以看出,IRun业务的调用方,不需要关心是如何实例化的。

二、DI框架如何管理Asp.NetCore2.0 Web应用的启动过程
一个极简的Web应用程序一般是这样的:
using Microsoft.AspNetCore.Hosting; namespace MyWebApi
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<StartUp>()
.Build(); host.Run();
}
}
}
从上面的代码中判断,DI框架的初始化和接口注册应该是在WebHostBuild.Build()方法中完成的,从命名就能看出,这是一个建造者模式,把内部复杂的构建方式隐藏了。我们去看一下这个方法的开源代码:
// 为了说明问题,代码略作调整,保留核心代码
public IWebHost Build()
{
// 初始化DI框架:估计里面预制了一些服务
IServiceCollection hostingServices = BuildCommonServices(out var hostingStartupErrors);
IServiceCollection applicationServices = hostingServices.Clone(); // 服务的提供者
ServiceProvider hostingServiceProvider = hostingServices.BuildServiceProvider(); AddApplicationServices(applicationServices, hostingServiceProvider); var host = new WebHost(
applicationServices,
hostingServiceProvider,
_options,
_config,
hostingStartupErrors); host.Initialize(); return host;
}
我们可以看到在WebHostBuild.Build()方法中,显示的初始化了DI框架,我们看一下DI框架初始化方法的源码,可以发现确实预制了一些服务:
// 为了说明问题,代码略作调整,保留核心代码
private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
{
// 配置选项
_options = new WebHostOptions(_config);
var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory);
var applicationName = _options.ApplicationName; // Initialize the hosting environment
_hostingEnvironment.Initialize(applicationName, contentRootPath, _options);
_context.HostingEnvironment = _hostingEnvironment; // 实例化DI框架
var services = new ServiceCollection(); // 预制环境参数服务到框架中
services.AddSingleton(_hostingEnvironment);
// 预制上下文插件到框架中
services.AddSingleton(_context);
// 预制配置管理服务到框架中
var builder = new ConfigurationBuilder()
.SetBasePath(_hostingEnvironment.ContentRootPath)
.AddInMemoryCollection(_config.AsEnumerable());
var configuration = builder.Build();
services.AddSingleton<IConfiguration>(configuration);
_context.Configuration = configuration;
// 预制诊断服务到框架中
var listener = new DiagnosticListener("Microsoft.AspNetCore");
services.AddSingleton<DiagnosticListener>(listener);
services.AddSingleton<DiagnosticSource>(listener);
// 预制其他服务到框架中
services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
services.AddTransient<IHttpContextFactory, HttpContextFactory>();
services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
services.AddOptions();
services.AddLogging();
// Conjure up a RequestServices
services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>();
services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
// Ensure object pooling is available everywhere.
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>(); return services;
}
从代码分析看WebHostBuilder做的事如下:
1. 定义了一些WebHost的配置项
2. 创建依赖注入的容器, 并预制一些service
三、其中WebServer就是作为服务进行注入的
回头再看WebServer的注册,使用的是UseKestrel:
using Microsoft.AspNetCore.Hosting; namespace MyWebApi
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<StartUp>()
.Build(); host.Run();
}
}
}
猜测也是作为服务进行注入的,我们来看Kestrel的开源代码:
public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder)
{
hostBuilder.UseLibuv(); return hostBuilder.ConfigureServices(services =>
{
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
services.AddSingleton<IServer, KestrelServer>();
});
}
从中能够看出WebServer是作为IServer接口进行注入的,而且是单例模式。
四、不难推断Startup也是作为服务进行注入的
极简的Web应用程序一般是这样的:
using Microsoft.AspNetCore.Hosting; namespace MyWebApi
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<StartUp>()
.Build(); host.Run();
}
}
}
我们来看开源代码:
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)
{
var startupAssemblyName = startupType.GetTypeInfo().Assembly.GetName().Name; return hostBuilder
.UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName)
.ConfigureServices(services =>
{
if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
{
services.AddSingleton(typeof(IStartup), startupType);
}
else
{
services.AddSingleton(typeof(IStartup), sp =>
{
var hostingEnvironment = sp.GetRequiredService<IHostingEnvironment>();
return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName));
});
}
});
}
从中能够看出Startup是作为IStartup接口进行注入的,而且是单例模式。
至此一个简单网站的初始化过程我们就基本清楚了!
05、NetCore2.0依赖注入(DI)之Web应用启动流程管理的更多相关文章
- 06、NetCore2.0依赖注入(DI)之整合Autofac
06.NetCore2.0依赖注入(DI)之整合Autofac 除了使用NetCore2.0系统的依赖注入(DI)框架外,我们还可以使用其他成熟的DI框架,如Autofac.Unity等.只要他们支持 ...
- 07、NetCore2.0依赖注入(DI)之生命周期
07.NetCore2.0依赖注入(DI)之生命周期 NetCore2.0依赖注入框架(DI)是如何管理注入对象的生命周期的?生命周期有哪几类,又是在哪些场景下应用的呢? -------------- ...
- Yii2.0 依赖注入(DI)和依赖注入容器的原理
依赖注入和依赖注入容器 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Serv ...
- .Net Core3.0依赖注入DI
构建ASP.NET Core应用程序的时候,依赖注入已成为了.NET Core的核心,这篇文章,我们理一理依赖注入的使用方法. 不使用依赖注入 首先,我们创建一个ASP.NET Core Mvc项目, ...
- .netCore2.0 依赖注入
依赖注入(ID)是一种实现对象及其合作者或者依赖想之间松散耦合的技术对于传统的方法来说,获取类的方法通常用new如下 public class DIController : Controller { ...
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
ADO.NET 一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data → DataTable, ...
- 依赖注入(DI)和Ninject
[ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 本文目录: 1.为什么需要依赖注入 2.什么是依赖注入 3.使用NuGet安装库 4.使用Ninject的一般步骤 5. ...
- 20181123_控制反转(IOC)和依赖注入(DI)
一. 控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...
- spring(3)------控制反转(IOC)/依赖注入(DI)
一.spring核心概念理解 控制反转: 控制反转即IoC (Inversion of Control).它把传统上由程序代码直接操控的对象的调用权交给容器.通过容器来实现对象组件的装配和管理. 所谓 ...
随机推荐
- intellij IDEA配置Tomcat
第一步:点击上方File选项找到Setting,在文本框中输入Tomcat,找到之后点击右下角的OK 第二步:再次找到Setting,在文本框中输入Application Servers找到后,单击 ...
- 【数据库】mysql数据库索引
文章归属:http://feiyan.info/16.html,我想自己去写了,但是发现此君总结的非常详细.直接搬过来了 关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基 ...
- 每天学习点--------第六天(2017-10-10) 摘要: mysql和Oracle的区别
1.自动增长数据类型的处理 Mysql有自动增长的数据类型,插入记录时不用操作此字段,会自动获取数据值.Oracle没有自动增长的数据类型,需要建立一个自动增长的序列号,插入记录时要把序列号的下一个值 ...
- MySQL升级-5.6升级到5.7版本&切换GTID模式
目前未在生产环境中升级过数据库版本,倒是在测试环境跟开发环境升级过. 可以通过mysqldump sql文件进行升级,也可以通过mysql_upgrade升级,前者耗时较长,且 ...
- java————面向对象概念
面向对象 OO:面向对象 OOP:面向对象编程 OOA:面向对象分析 OOD:面向对象设计 面向对象的特征 继承,封装,多态 什么是对象? 对象是存在的具体实体,具有明确定义的特征和行为. 万物皆对象 ...
- 听翁恺老师mooc笔记(14)--格式化的输入与输出
关于C语言如何做文件和底层操作: 文件操作,从根本上说,和C语言无关.这部分的内容,是教你如何使用C语言的标准库所提供的一系列函数来操作文件,最基本的最原始的文件操作.你需要理解,我们在这部分所学习的 ...
- Django 视图层
URL映射 1.分布式url映射 include()函数提供分布式url映射功能,使URL映射可以被编写在多个url.py文件中 from django.conf.urls import url fr ...
- 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)
标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...
- python 操作MongoDB
安装MongoDB 启动数据库:安装完成指定数据库存放路径 mongod.exe --dbpath c:\data\db进入目录后运行mongo.exe 成功 创建数据库 > use mydb ...
- Environment.getExternalStorageDirectory()
Environment.getExternalStorageDirectory()得到的是storage/emulated/0