.Net Core — 依赖注入
在.NET Core 中 依赖注入Dependency-Injection)作为基础知识,在.Net Core中无处不在;这么重要的知识接下来就了解和在.Net Core中使用。
一、依赖注入
说到依赖注入(Dependency Injection,以下简称DI),就必须说IoC(Inverse of Control);这两个概念很容易搞混。
IoC:主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用“好莱坞原则”是应用程序以被动的方式实现对流程的定制。
DI:服务的消费者利用一个独立的容器(Container)来获取所需的服务对象,容器自身在提供服务对象的过程中会自动完成依赖的解析与注入
核心功能:服务注册和服务提供
二、DI在.Net Core中实现
在.Net Core中主要 Microsoft.Extensions.DependencyInjection 中实现DI相关功能,可以在你的项目中单独使用它
核心分为两个组件:IServiceCollection和 IServiceProvider

IServiceCollection:负责服务的注册;主要扩展方法如下:
public static class ServiceCollectionServiceExtensions
{
public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType, Type implementationType);
public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, Type implementationType);
public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Type implementationType);
……
}
ServiceCollectionServiceExtensions扩展类中包含了这三个方法的多种重载方法,那么这三个方法分别什么含义呢?
IServiceProvider:负责服务的获取;主要方法:
public interface IServiceProvider
{
//获取服务
object GetService(Type serviceType);
}
在IServiceCollection中我们看到了主要到三个方法这些方法的意义是什么呢?
生命周期:
.NET Core DI 为我们提供的实例生命周其包括三种:
- Transient: 每一次GetService都会创建一个新的实例
- Scoped: 在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内)
- Singleton: 整个应用程序生命周期以内只创建一个实例(单例)
三、Asp.Net Core 中应用
以上一篇审计日志源码作为示例:
- 添加日志仓储接口和实现:
//仓储接口
public interface IRepository<T>
{
T Save(T entity);
} //审计日志仓储实现
public class AuditLogRepository : IRepository<AuditInfo>
{
AuditLogDBContent _auditLogDB;
public AuditLogRepository(AuditLogDBContent auditLogDB)
{
_auditLogDB = auditLogDB;
} public AuditInfo Save(AuditInfo entity)
{
var retEntity = _auditLogDB.AuditInfos.Add(entity);
_auditLogDB.SaveChanges();
return retEntity.Entity;
}
} - 实现定义服务接口和实现
//审计日志服务接口
public interface IAuditLogService
{
Task SaveAsync(AuditInfo auditInfo);
} //审计日志服务实现
public class AuditLogService : IAuditLogService
{
IRepository<AuditInfo> _repository;
//依赖注入:IRepository<AuditInfo>
public AuditLogService(IRepository<AuditInfo> repository)
{
_repository = repository;
} public async Task SaveAsync(AuditInfo auditInfo)
{
_repository.Save(auditInfo);
}
} - 在Startup中注入定义的相关服务:
public void ConfigureServices(IServiceCollection services)
{
//审计日志存储数据库
services.AddDbContext<AuditLogDBContent>(options =>
{
string conn = Configuration.GetConnectionString("LogDB");
options.UseSqlite(conn, options =>
{
options.MigrationsAssembly("AuditLogDemo");
});
}); //依赖注入:审计日志仓储和审计日志服务
services.AddScoped<IRepository<AuditInfo>, AuditLogRepository>();
services.AddScoped<IAuditLogService, AuditLogService>(); services.AddControllers(options =>
{
options.Filters.Add(typeof(AuditLogActionFilter));
});
}可以看出当前注入服务不多,相对简单还好,但项目中仓储和服务数量肯定比示例数量多,不可能每个都像这样手工注入。
那么有什么好的解决办法呢?接着往下看
四、批量注入实现方式
- 自己实现批量注入
public static class DIHelper
{
/// <summary>
/// 注入服务
/// </summary>
/// <param name="services"></param>
/// <param name="interfaceAssembly"></param>
/// <param name="implementAssembly"></param>
public static void AddScoped(this IServiceCollection services, Assembly interfaceAssembly, Assembly implementAssembly)
{
var interfaces = interfaceAssembly.GetTypes().Where(t => t.IsInterface);
var implements = implementAssembly.GetTypes();
foreach (var item in interfaces)
{
var type = implements.FirstOrDefault(x => item.IsAssignableFrom(x));
if (type != null)
{
services.AddScoped(item, type);
}
}
} /// <summary>
/// 注入服务
/// </summary>
/// <param name="services"></param>
/// <param name="interfaceAssembly"></param>
/// <param name="implementAssembly"></param>
public static void AddSingleton(this IServiceCollection services, Assembly interfaceAssembly, Assembly implementAssembly)
{
var interfaces = interfaceAssembly.GetTypes().Where(t => t.IsInterface);
var implements = implementAssembly.GetTypes();
foreach (var item in interfaces)
{
var type = implements.FirstOrDefault(x => item.IsAssignableFrom(x));
if (type != null)
{
services.AddSingleton(item, type);
}
}
} /// <summary>
/// 注入服务
/// </summary>
/// <param name="services"></param>
/// <param name="interfaceAssembly"></param>
/// <param name="implementAssembly"></param>
public static void AddTransient(this IServiceCollection services, Assembly interfaceAssembly, Assembly implementAssembly)
{
var interfaces = interfaceAssembly.GetTypes().Where(t => t.IsInterface);
var implements = implementAssembly.GetTypes();
foreach (var item in interfaces)
{
var type = implements.FirstOrDefault(x => item.IsAssignableFrom(x));
if (type != null)
{
services.AddTransient(item, type);
}
}
}
}
使用方式:
services.AddScoped(Assembly.Load("xxxx.IService"), Assembly.Load("xxxx.Service"));
services.AddScoped(Assembly.Load("xxxx.IService"), Assembly.Load("xxxx.Service"));
- Autofac实现批量注入
添加Nuget包:

1、添加Autofac模型实现:
/// <summary>
/// 注册Autofac模块
/// </summary>
public class AutofacModuleRegister : Autofac.Module
{
/// <summary>
/// 重写Autofac管道Load方法,在这里注册注入
/// </summary>
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(GetAssemblyByName("AuditLog.EF"))
.Where(a => a.Name.EndsWith("Repository"))
.AsImplementedInterfaces(); builder.RegisterAssemblyTypes(GetAssemblyByName("AuditLog.Application"))
.Where(a => a.Name.EndsWith("Service"))
.AsImplementedInterfaces(); //注册MVC控制器(注册所有到控制器,控制器注入,就是需要在控制器的构造函数中接收对象)
builder.RegisterAssemblyTypes(GetAssemblyByName("AuditLogDemo"))
.Where(a => a.Name.EndsWith("Controller"))
.AsImplementedInterfaces();
} /// <summary>
/// 根据程序集名称获取程序集
/// </summary>
/// <param name="assemblyName">程序集名称</param>
public static Assembly GetAssemblyByName(string assemblyName)
{
return Assembly.Load(assemblyName);
}
}
2、使用Autofac来实现依赖注入
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
//改用Autofac来实现依赖注入
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
3、调整Statup文件:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
/// <summary>
/// autofac容器
/// </summary>
public ILifetimeScope AutofacContainer { get; private set; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//审计日志存储
services.AddDbContext<AuditLogDBContent>(options =>
{
string conn = Configuration.GetConnectionString("LogDB");
options.UseSqlite(conn, options =>
{
options.MigrationsAssembly("AuditLogDemo");
});
}); //依赖注入
//Scoped:一个请求创建一个
//services.AddScoped<IRepository<AuditInfo>, AuditLogRepository>();
////每次创建一个
//services.AddTransient<IAuditLogService, AuditLogService>(); services.AddControllers(options =>
{
options.Filters.Add(typeof(AuditLogActionFilter));
}); } /// <summary>
/// 配置容器:在ConfigureServices后执行
/// </summary>
/// <param name="builder"></param>
public void ConfigureContainer(ContainerBuilder builder)
{
// 直接用Autofac注册我们自定义的
builder.RegisterModule(new AutofacModuleRegister());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//autofac 新增 可选
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
}); }
}
到此Autofac批量实现注入服务完成。
参考:
https://github.com/cwsheng/AuditLogDemo
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection
https://www.cnblogs.com/artech/p/di-4-asp-net-core.html
.Net Core — 依赖注入的更多相关文章
- # ASP.NET Core依赖注入解读&使用Autofac替代实现
标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...
- net core 依赖注入问题
net core 依赖注入问题 最近.net core可以跨平台了,这是一个伟大的事情,为了可以赶上两年以后的跨平台部署大潮,我也加入到了学习之列.今天研究的是依赖注入,但是我发现一个问题,困扰我很久 ...
- NET Core依赖注入解读&使用Autofac替代实现
NET Core依赖注入解读&使用Autofac替代实现 标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. ...
- 实现BUG自动检测 - ASP.NET Core依赖注入
我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...
- [译]ASP.NET Core依赖注入深入讨论
原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...
- asp.net core 依赖注入几种常见情况
先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...
- ASP.NET Core依赖注入——依赖注入最佳实践
在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...
- 自动化CodeReview - ASP.NET Core依赖注入
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...
- ASP.NET Core 依赖注入最佳实践——提示与技巧
在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...
- ASP.NET Core依赖注入最佳实践,提示&技巧
分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...
随机推荐
- MySQL ERROR 1040: Too many connections
如题,本章主要讲下当服务器出现 ERROR 1040: Too many connections错误时的一些处理心得. max_connections查看 ## 查看最大连接数 SHOW VARIAB ...
- 第2章 Python编程基础知识 第2.1节 简单的Python数据类型、变量赋值及输入输出
第三节 简单的Python数据类型.变量赋值及输入输出 Python是一门解释性语言,它的执行依赖于Python提供的执行环境,前面一章介绍了Python环境安装.WINDOWS系列Python编辑和 ...
- 快速理解Python中使用百分号占位符的字符串格式化方法中%s和%r的输出内容的区别
<Python中使用百分号占位符的字符串格式化方法中%s和%r的输出内容有何不同?>老猿介绍了二者的区别,为了快速理解,老猿在此使用另外一种方式补充说明一下: 1.使用%r是调用objec ...
- VirtualBox安装Centos出现E_FAIL (0x80004005)的解决方法
问题描述:UUID已经存在 Cannot register the hard disk 'F:\hadoop\VirtualBox-centos\centos6.4\centos6.4.vdi' {0 ...
- neo4j数据库数据转移,从阿里云转移到windows服务器
1.从阿里云迁移neo4j时需停掉neo4j数据库,在neo4j的bin目录下输入 ./neo4j stop 2.将数据备份到一个文件中 ./neo4j-admin dump --database=g ...
- MySQL(14)---Docker搭建MySQL主从复制(一主一从)
Docker搭建MySQL主从复制(一主一从) 上一篇博客写了MYSQL主从复制原理 : MySQL(13)---MYSQL主从复制原理 这篇我们来写 Docker搭建MYSQL主从复制(一主一从) ...
- 【题解】P3631 [APIO2011]方格染色
很有意思的一道题,所以单独拿出来了. 完整分享看 这里 题目链接 luogu 题意 有一个包含 \(n \times m\) 个方格的表格.要将其中的每个方格都染成红色或蓝色.表格中每个 \(2 \t ...
- NOI Online #1 入门组 魔法
全网都是矩阵快速幂,我只会倍增DP 其实这题与 AcWing 345. 牛站 还是比较像的,那题可以矩阵快速幂 / 倍增,这题也行. 先 \(Floyd\) 预处理两点之间不用魔法最短距离 \(d_{ ...
- AcWing 316 .减操作
题目链接 大型补档计划 没想出来去看题解了... 关键是发现无论怎样括号嵌套,每个元素始终只有对答案的贡献为 + a[i] 或者 - a[i]. 而且第一个必然贡献是 +1, 第二个必然是 -1. 所 ...
- 微信小程序-卡券开发(前端)
刚完成一个微信小程序卡券开发的项目.下面记录开发前,自己困惑的几个问题. 因为我只负责了前端.所以下面主要是前端的工作. 项目概述:按照设计图开发好首页上的优惠券列表,点击某个优惠券,输入手机号,点击 ...