全面理解 ASP.NET Core 依赖注入
一、什么是依赖注入
- 1.1 依赖
- 1.2 什么注入
- 为什么反转
- 何为容器
二、.NET Core DI
- 2.1 实例的注册
- 2.2 实例生命周期之单例
- 2.3 实例生命周期之Tranisent
- 2.4 实例生命周期之Scoped
三、DI在ASP.NET Core中的应用
- 3.1 在Startup类中初始化
- 3.2 Controller中使用
- 3.3 View中使用
- 3.4 通过HttpContext来获取
四、如何替换其它的Ioc容器
一、什么是依赖注入(Denpendency Injection)
1.1依赖

1.2 什么是注入
- private ILoginService<ApplicationUser> _loginService;
- public AccountController()
- {
- _loginService = new EFLoginService()
- }
大师说,这样不好。你不应该自己创建它,而是应该由你的调用者给你。于是你通过构造函数让外界把这两个依赖传给你。
- public
- AccountController(ILoginService<ApplicationUser> loginService)
- {
- _loginService = loginService;
- }
把依赖的创建丢给其它人,自己只负责使用,其它人丢给你依赖的这个过程理解为注入。
1.3 为什么要反转?

- public
- AccountController(ILoginService<ApplicationUser> loginService)
- {
- _loginService = loginService;
- }
// 用Redis来替换原来的EF登录 var controller = new AccountController(new RedisLoginService()); controller.Login(userName, password);
1.4 何为容器
- 绑定服务与实例之间的关系
- 获取实例,并对实例进行管理(创建与销毁)

二、.NET Core DI
2.1 实例的注册
- IServiceCollection 负责注册
- IServiceProvider 负责提供实例
- var serviceCollection = new ServiceCollection()
- .AddTransient<ILoginService, EFLoginService>()
- .AddSingleton<ILoginService, EFLoginService>()
- .AddScoped<ILoginService, EFLoginService>();
- public interface IServiceCollection : IList<ServiceDescriptor>
- {
- }
我们上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的扩展方法, 都是往这个List里面添加ServiceDescriptor。
- private static IServiceCollection Add(
- IServiceCollection collection,
- Type serviceType,
- Type implementationType,
- ServiceLifetime lifetime)
- {
- var descriptor =
- new ServiceDescriptor(serviceType, implementationType, lifetime);
- collection.Add(descriptor);
- return collection;
- }
2.2 实例的生命周期之单例
- Transient: 每一次GetService都会创建一个新的实例
- Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内)
- Singleton :整个应用程序生命周期以内只创建一个实例
- public enum ServiceLifetime
- {
- Singleton,
- Scoped,
- Transient
- }
- public interface IOperation
- {
- Guid OperationId { get; }
- }
- public interface IOperationSingleton : IOperation { }
- public interface IOperationTransient : IOperation{}
- public interface IOperationScoped : IOperation{}
我们的 Operation实现很简单,可以在构造函数中传入一个Guid进行赋值,如果没有的话则自已New一个 Guid。
- public class Operation :
- IOperationSingleton,
- IOperationTransient,
- IOperationScoped
- {
- private Guid _guid;
- public Operation() {
- _guid = Guid.NewGuid();
- }
- public Operation(Guid guid)
- {
- _guid = guid;
- }
- public Guid OperationId => _guid;
- }
在程序内我们可以多次调用ServiceProvider的GetService方法,获取到的都是同一个实例。
- var services = new ServiceCollection();
- // 默认构造
- services.AddSingleton<IOperationSingleton, Operation>();
- // 自定义传入Guid空值
- services.AddSingleton<IOperationSingleton>(
- new Operation(Guid.Empty));
- // 自定义传入一个New的Guid
- services.AddSingleton <IOperationSingleton>(
- new Operation(Guid.NewGuid()));
- var provider = services.BuildServiceProvider();
- // 输出singletone1的Guid
- var singletone1 = provider.GetService<IOperationSingleton>();
- Console.WriteLine($"signletone1: {singletone1.OperationId}");
- // 输出singletone2的Guid
- var singletone2 = provider.GetService<IOperationSingleton>();
- Console.WriteLine($"signletone2: {singletone2.OperationId}");
- Console.WriteLine($"singletone1 == singletone2 ? : { singletone1 == singletone2 }");
我们对IOperationSingleton注册了三次,最后获取两次,大家要注意到我们获取到的始终都是我们最后一次注册的那个给了一个Guid的实例,前面的会被覆盖。
2.3 实例生命周期之Tranisent
这次我们获取到的IOperationTransient为两个不同的实例。

2.4 实例生命周期之Scoped
- var services = new ServiceCollection()
- .AddScoped<IOperationScoped, Operation>()
- .AddTransient<IOperationTransient, Operation>()
- .AddSingleton<IOperationSingleton, Operation>();
接下来我们用ServiceProvider.CreateScope方法创建一个Scope
- var provider = services.BuildServiceProvider();
- using (var scope1 = provider.CreateScope())
- {
- var p = scope1.ServiceProvider;
- var scopeobj1 = p.GetService<IOperationScoped>();
- var transient1 = p.GetService<IOperationTransient>();
- var singleton1 = p.GetService<IOperationSingleton>();
- var scopeobj2 = p.GetService<IOperationScoped>();
- var transient2 = p.GetService<IOperationTransient>();
- var singleton2 = p.GetService<IOperationSingleton>();
- Console.WriteLine(
- $"scope1: { scopeobj1.OperationId }," +
- $"transient1: {transient1.OperationId}, " +
- $"singleton1: {singleton1.OperationId}");
- Console.WriteLine($"scope2: { scopeobj2.OperationId }, " +
- $"transient2: {transient2.OperationId}, " +
- $"singleton2: {singleton2.OperationId}");
- }
接下来
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient1: fb35f570-713e-43fc-854c-972eed2fae52,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient2: 2766a1ee-766f-4116-8a48-3e569de54259,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
如果再创建一个新的Scope运行,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient2: 74c37151-6497-4223-b558-a4ffc1897d57,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225

三、DI在ASP.NET Core中的应用
3.1在Startup类中初始化
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddTransient<ILoginService<ApplicationUser>,
- EFLoginService>();
- services.AddMvc();
- )
ASP.NET Core的一些组件已经提供了一些实例的绑定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的扩展方法。
- public static IMvcBuilder AddMvc(this IServiceCollection services)
- {
- if (services == null)
- {
- throw new ArgumentNullException(nameof(services));
- }
- var builder = services.AddMvcCore();
- builder.AddApiExplorer();
- builder.AddAuthorization();
- AddDefaultFrameworkParts(builder.PartManager);
- ...
- }
3.2 Controller中使用
- private ILoginService<ApplicationUser> _loginService;
- public AccountController(
- ILoginService<ApplicationUser> loginService)
- {
- _loginService = loginService;
- }
我们只要在控制器的构造函数里面写了这个参数,ServiceProvider就会帮我们注入进来。这一步是在Mvc初始化控制器的时候完成的,我们后面再介绍到Mvc的时候会往细里讲。
3.3 View中使用
- @using MilkStone.Services;
- @model MilkStone.Models.AccountViewModel.LoginViewModel
- @inject ILoginService<ApplicationUser> loginService
- <!DOCTYPE html>
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head></head>
- <body>
- @loginService.GetUserName()
- </body>
- </html>
3.4 通过 HttpContext来获取实例
- HttpContext.RequestServices.GetService<ILoginService<ApplicationUser>>();
四、如何替换其它的Ioc容器
- builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
- builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
这会给我们的初始化带来一些便利性,我们来看看如何替换Autofac到ASP.NET Core。我们只需要把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可。而返回的则是一个AutoServiceProvider。
- public IServiceProvider ConfigureServices(
- IServiceCollection services){
- services.AddMvc();
- // Add other framework services
- // Add Autofac
- var containerBuilder = new ContainerBuilder();
- containerBuilder.RegisterModule<DefaultModule>();
- containerBuilder.Populate(services);
- var container = containerBuilder.Build();
- return new AutofacServiceProvider(container);
- }
4.1 有何变化

全面理解 ASP.NET Core 依赖注入的更多相关文章
- 全面理解 ASP.NET Core 依赖注入 (转载)
DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET Core的DI实现以及对实例 ...
- 深入理解ASP.NET Core依赖注入
概述 ASP.NET Core可以说是处处皆注入,本文从基础角度理解一下原生DI容器,及介绍下怎么使用并且如何替换官方提供的默认依赖注入容器. 什么是依赖注入 百度百科中对 ...
- 理解ASP.NET Core 依赖注入
目录: 一.什么是依赖注入 1.1.什么是依赖? 1.2. 什么是注入? 1.3.依赖注入解决的问题 二.服务的生命周期(.Net Core DI) 三.替换默认服务容器 3.1.为什么替换默认服务容 ...
- asp.net core 依赖注入几种常见情况
先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...
- [译]ASP.NET Core依赖注入深入讨论
原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...
- ASP.NET Core依赖注入——依赖注入最佳实践
在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...
- # ASP.NET Core依赖注入解读&使用Autofac替代实现
标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...
- 实现BUG自动检测 - ASP.NET Core依赖注入
我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...
- 自动化CodeReview - ASP.NET Core依赖注入
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...
随机推荐
- EasyUI DataGrid使用示例
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="EasyUIDemo.aspx. ...
- ajax请求service报405错误 - 【服务器不允许的方法】
产生原因:web服务器找不到service方法处理请求. 检查方向: ① service方法名称写错 ② service方法参数类型与标准不一致 ③ service方法异常,返回值类型和标准不一致 ④ ...
- 即时通信系统Openfire分析之八:集群管理
前言 在第六章<路由表>中,客户端进行会话时,首先要获取对方的Session实例.获取Session实例的方法,是先查找本地路由表,若找不到,则通过路由表中的缓存数据,由定位器获取. 路由 ...
- 简易RPC框架-客户端限流配置
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- Java常用类(一)之Object类详解
大家都知道Object是所有类的父类,任何类都默认继承Object 理论上Object类是所有类的父类,即直接或间接的继承java.lang.Object类.由于所有的类都继承在Object类,因此省 ...
- mysql批量更新数据,即:循环select记录然后更新某一字段
原因: 今天遇到一个问题:一个数据表case_folder_info想要实现自定义排序功能,就在表里新加了一个字段SORT_NUMBER,由于表里存在已有数据,所以这个SORT_NUMBER字段都为空 ...
- 2年Java开发工作经验面试总结
最近换了个公司,从三月底开始面,面到四月底,面了有快二十家公司.我是一个喜欢总结经验的人,每经过一场面试,我在回来的路上都会仔细回想今天哪些问题可以答的更好,或者哪些问题是自己之前没遇到过的,或者是哪 ...
- 80端口被系统服务【kernel&System】占用解决方案
netstat -ano | findstr port //查看端口占用情况 tasklist | findstr port //查看端口被占用的具体服务名 运行net stop http ...
- mybatis 的mapper配置文件sql语句中, 有时用到 大于, 小于等等
一, 用<![CDATA[ ]]>标识,例如: <if test="create_timeStart != null and create_timeStart != ' ...
- onclick事件触发 input type=“file” 上传文件
添加按钮: <input type="button" name="button" value="浏览" onclick="j ...