.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应用程序中使用依赖注入的经验和建议. ...
随机推荐
- moviepy音视频剪辑:视频剪辑基类VideoClip的__init__构造方法参数has_constant_size的作用
☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑模块的视频剪辑基类VideoClip构造方法: __init__(self, make_frame=None, ismask=Fals ...
- 记账本APP小升级
增加了显示当月总收入和总支出的功能,增加了选择收支类型的功能,删去了删除账目后恢复的功能. 1.数据库的升级 1.entity 添加了一个收支类型的字段: package com.example.ca ...
- kubernetes 中的证书工作机制
一文带你彻底厘清 Kubernetes 中的证书工作机制 搬砖者: 张首富 时 间: 2020-05-26 w x: y18163201 原文地址:https://zhaohuabing.com/po ...
- 《Eroico》关卡与操作设计
操作设计: 没有给明操作教程,操作全靠蒙,只有改建的位置可以看到. 但游戏的难度并没有给玩家适应操作感,随着难度提升怪物血量增厚,但怪物并没有僵直英雄却有僵直.第一个小猫妖便给了玩家一个痛击. 方向键 ...
- 题解-Cats Transport
题解-Cats Transport Cats Transport 有 \(n\) 个山丘,\(m\) 只猫子,\(p\) 只铲屎官.第 \(i-1\) 个山丘到第 \(i\) 个山丘的距离是 \(d_ ...
- pyppeteer 登录一般网站 并利用 http方法获取登录页面的验证码
主函数 新建浏览器,进行登录,由于验证码的识别准确率不是百分之百,需要多次尝试. async def main(self, username, pwd, url): # 定义main协程函数, log ...
- html+css一些简单案例:爱心点击,盒子模型,2d动画
canvas绘制爱心 效果预览 上代码 <!doctype html> <html> <head> <title>HTML5 Canvas爱心飘动动画特 ...
- idea 最好用的插件
1.lombok 不用写get,set方法 2.MyBatisCodeHelperPro 3.Rainbow Brackets 彩虹括号 5.activate-power-mode 动感打字 7.Ba ...
- js上 十一、循环语句-2
11-1.跳转语句 在js中,有如下四种跳转语句: ü break ü continue break:结束本层循环 continue:跳过(结束)本次循环,继续进入下一次循环 就是两个关键字 #11- ...
- 关于ABAP和JSON互相转换
关于ABAP数据结构和JSON格式转换,需要用到标准的类/UI2/CL_JSON一下两个方法, DESERIALIZE是把JSON格式转换成ABAP数据结构,SERIALIZE是把ABAP数据结构转换 ...