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应用启动流程管理的更多相关文章

  1. 06、NetCore2.0依赖注入(DI)之整合Autofac

    06.NetCore2.0依赖注入(DI)之整合Autofac 除了使用NetCore2.0系统的依赖注入(DI)框架外,我们还可以使用其他成熟的DI框架,如Autofac.Unity等.只要他们支持 ...

  2. 07、NetCore2.0依赖注入(DI)之生命周期

    07.NetCore2.0依赖注入(DI)之生命周期 NetCore2.0依赖注入框架(DI)是如何管理注入对象的生命周期的?生命周期有哪几类,又是在哪些场景下应用的呢? -------------- ...

  3. Yii2.0 依赖注入(DI)和依赖注入容器的原理

    依赖注入和依赖注入容器 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Serv ...

  4. .Net Core3.0依赖注入DI

    构建ASP.NET Core应用程序的时候,依赖注入已成为了.NET Core的核心,这篇文章,我们理一理依赖注入的使用方法. 不使用依赖注入 首先,我们创建一个ASP.NET Core Mvc项目, ...

  5. .netCore2.0 依赖注入

    依赖注入(ID)是一种实现对象及其合作者或者依赖想之间松散耦合的技术对于传统的方法来说,获取类的方法通常用new如下 public class DIController : Controller { ...

  6. 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, ...

  7. 依赖注入(DI)和Ninject

    [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 本文目录: 1.为什么需要依赖注入 2.什么是依赖注入 3.使用NuGet安装库 4.使用Ninject的一般步骤 5. ...

  8. 20181123_控制反转(IOC)和依赖注入(DI)

    一.   控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...

  9. spring(3)------控制反转(IOC)/依赖注入(DI)

    一.spring核心概念理解 控制反转: 控制反转即IoC (Inversion of Control).它把传统上由程序代码直接操控的对象的调用权交给容器.通过容器来实现对象组件的装配和管理. 所谓 ...

随机推荐

  1. 笔记:I/O流-对象序列化

    Java 语言支持一种称为对象序列化(Object Serialization)的非常通用的机制,可以将任何对象写入到流中,并在之后将其读回,首先需要支持对象序列化的类,必须继承与 Serializa ...

  2. 笔记:Struts2 拦截器

    配置拦截器 Struts.xml 配置文件中,使用<interceptor-/>来定义拦截器,有属性 name 表示拦截器的名称,class 表示拦截器的具体首先类,可以使用<par ...

  3. [mysql] MySQL解压缩安装步骤

    以前装的MySQL出问题了,只好卸载了. 又下载了一个mysql-5.6.24-win32.1432006610.zip.msi文件直接安装就行了.这里需要解压到指定目录,配置后可使用. 环境变量配置 ...

  4. css3控制div上下跳动-效果图

    效果图演示,源代码    

  5. VC++开发AutoCAD 2018/objectARX 用向导新建项目无法新建的问题

    话说笔者最近想用新机子上装的AutoCAD ObjectARX 2018来进行二次开发,兴致勃勃安装了ARX API和向导, 然后打开VS2015,新建项目,无法新建. 折腾了一下,还是没有解决,后面 ...

  6. 2018.3.29 DIV位置调整代码

    <!DOCTYPE html><html>    <head>        <meta charset="UTF-8">      ...

  7. 铜齿铁牙UP计划

    铜齿铁牙UP计划 我在""做教练"之好声音训练"给出了老师.播音主持学习者,声乐学习者科学用声三要点: 用气发声 共鸣发声 虚实结合 用气发声首先要学会腹式呼吸 ...

  8. beta冲刺3

    一,昨天的问题: 页面整理还没做 我的社团这边的后台数据库未完成,前端代码修改未完成. 二,今天已完成 页面整理基本完成,把登陆独立出来了,然后基本处理掉了多余页面(反正也没几个--) 我的社团这边试 ...

  9. C语言的第二次作业

    一.PTA实验作业 题目1. 计算分段函数 本题目要求计算下列分段函数f(x)的值: 1.本题代码 #include<stdio.h> #include<math.h> int ...

  10. 课后练习:C语言实现Linux命令——od

    课后练习:C语言实现Linux命令--od --------CONTENTS-------- 题目详情与分析 设计思路 遇到的问题及解决 待实现的设想与思考 学习反思与感悟 附1:myod.c「1.0 ...