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. NumPy入门

    import numpy as np 数组与标量之间的运算作用于数组的每一个元素.

  2. ELK学习笔记(四)SpringBoot+Logback+Redis+ELK实例

    废话不多说,直接上干货,首先看下整体应用的大致结构.(整个过程我用到了两台虚拟机  应用和Shipper 部署在192.168.25.128 上 Redis和ELK 部署在192.168.25.129 ...

  3. 【Bootstrap】bootstrap-fileinput上传文件插件

    [bootstrap-fileinput] 这是个据传最好用的bootstrap相关联的文件上传控件,支持拖曳上传,多线程上传,上传文件预览等等功能. 首先还是说一下要引入的一些文件: <lin ...

  4. 网络通信 --> Linux 五种IO模型

    Linux 五种IO模型 聊聊Linux 五种IO模型

  5. canvas星空和图形变换

    图形变换. 一.画一片星空 先画一片canvas.width宽canvas.height高的黑色星空,再画200个随机位置,随机大小,随机旋转角度的星星. window.onload=function ...

  6. 目前微服务/REST的最佳技术栈

    服务端 日期 编程语言 Web Framework DbAccess/ORM 数据库 2017-09-07 Node.js 8.4 Koa 2.3 sequelize 4.8 MySQL 2017-0 ...

  7. [poj2342]Anniversary party_树形dp

    Anniversary party poj-2342 题目大意:没有上司的舞会原题. 注释:n<=6000,-127<=val<=128. 想法:其实就是最大点独立集.我们介绍树形d ...

  8. Dependency Walker的替代品Dependencies

    在c++时代, Dependency Walker基本上是大部分程序员必备的工具之一,很可惜的是从2006起就不更新了.而且只支持vc的名字undemangle, https://github.com ...

  9. Beta冲刺 第六天

    Beta冲刺 第六天 1. 昨天的困难 1.对于设计模式的应用不熟悉,所以在应用上出现了很大的困难. 2.SSH中数据库的管理是用HQL语句实现的,所以在多表查询时出现了很大的问题. 3.页面结构太凌 ...

  10. Java Collections API和泛型

    Java Collections API和泛型 数据结构和算法 学会一门编程语言,你可以写出一些可以工作的代码用计算机来解决一些问题,然而想要优雅而高效的解决问题,就要学习数据结构和算法了.当然对数据 ...