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).它把传统上由程序代码直接操控的对象的调用权交给容器.通过容器来实现对象组件的装配和管理. 所谓 ...
随机推荐
- ajax利用FormData异步文件提交
通常情况下,我们上传文件都会使用form表单来提交文件.但有时候,我们会有异步提交文件的需求,在这种情况下,我们就需要新建一个Formdata来提交文件,后台如果使用的是PHP的话可以使用$_FILE ...
- [poj2406]Power Strings_hash
Power Strings poj-2406 题目大意:询问一个字符串最多几个相同且连续的字符串构成(Eg:abababab由4个构成,abcd由1个构成). 注释:字符串长度为n,$1\le n\l ...
- Jmeter 多用户同时登陆
在做性能测试的时候,很多情况需要多用户同时登录,下单,那怎么实现多用户的同时登录呢 可以通过CSV Data Set Config组件实现参数化登录 1.新建一个存放用户名和密码的文件, 和jmete ...
- vue-过渡动画
本篇资料参考于官方文档: http://cn.vuejs.org/guide/transitions.html 概述: Vue 在跳转页面时,提供多种不同方式的动画过渡效果. ●in-out:新元素先 ...
- java使用io创建文件与删除文件的工具类
java中对于文件的操作,是再常见不过了.以下代码是自己代码中所用到的工具类,仅供参考. import java.io.File; import java.io.IOException; /** * ...
- 宝塔Linux面板命令大全
安装宝塔 Centos安装脚本 yum install -y wget && wget -O install.sh http://download.bt.cn/install/inst ...
- 关于伪类after后续追加,实现js事件(如点击事件)
实现情况为:点击"编辑"后,"编辑"文字变成"完成",再点击伪类元素后的"完成",此时的"完成"应该 ...
- web.config中configSections section节 -Z
由于最近一个项目的数据库变动比较频繁, 为了减少数据层的负担, 打算采用.net的MVC框架, 使用LINQ对付数据层. 这个框架的web.config文件里出现了configSectio ...
- 实验四:Android 开发基础
实验四:实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 张旭升 学号:20162329 指导教师:娄嘉鹏 王志强 实验日期:5月26日 实验密级: 非密级 预习程度: 已预习 必修/选修 ...
- 201621123050 《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 答:接口.has-a.comparable 1.2 尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多的字. ...