在.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 — 依赖注入的更多相关文章

  1. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  2. net core 依赖注入问题

    net core 依赖注入问题 最近.net core可以跨平台了,这是一个伟大的事情,为了可以赶上两年以后的跨平台部署大潮,我也加入到了学习之列.今天研究的是依赖注入,但是我发现一个问题,困扰我很久 ...

  3. NET Core依赖注入解读&使用Autofac替代实现

    NET Core依赖注入解读&使用Autofac替代实现 标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. ...

  4. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  5. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  6. asp.net core 依赖注入几种常见情况

    先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...

  7. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  8. 自动化CodeReview - ASP.NET Core依赖注入

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...

  9. ASP.NET Core 依赖注入最佳实践——提示与技巧

    在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...

  10. ASP.NET Core依赖注入最佳实践,提示&技巧

    分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...

随机推荐

  1. 用java以正确的姿势刷CSP

    许多程序算法考试中,用java是个不错的选择,它几乎实现了所有c++能实现的,所以越来越受Acmer的欢迎.总结一下用到的一些技巧和方法.更多关于csp的可参考海岛blog|皮卡丘 1. 输出 规格化 ...

  2. PyQt(Python+Qt)学习随笔:QTableWidgetItem的构造方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTableWidgetItem类为QTableWidget类的项实例类,用于保存表格部件的信息.项 ...

  3. PyQt(Python+Qt)学习随笔:QTreeView树形视图的sortingEnabled属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTreeView树形视图的sortingEnabled属性用于控制视图中的数据是否启用按表头排序, ...

  4. 原生JS学习之秒表、日历

    Tips:涉及知识点:Date   setInterval    DOM    秒表 效果图: 简单构造出草图 Html代码 1 <!DOCTYPE html> 2 <html> ...

  5. Scrum 冲刺 第七篇

    Scrum 冲刺 第七篇 每日会议照片 昨天已完成工作 队员 昨日完成任务 黄梓浩 初步完成app首页模块的搭建 黄清山 完成部分个人界面模块数据库的接口 邓富荣 完成部分个人界面接口 钟俊豪 完成部 ...

  6. Python(二) 安装PIL

    1. 在使用PIL之前我们需先安装PIL. 在cmd中使用 pip 指令,竟报错,没有这个指令 2. 我就给环境变量加上这个指令,找到本机上安装python的位置,找到scrips文件夹, 看到里面的 ...

  7. 【题解】AcWing 193. 算乘方的牛

    原题链接 题目描述 约翰的奶牛希望能够非常快速地计算一个数字的整数幂P(1 <= P <= 20,000)是多少,这需要你的帮助. 在它们计算得到最终结果的过程中只能保留两个工作变量用于中 ...

  8. 落谷P3041 [USACO12JAN]Video Game G

    题目链接 多模式匹配问题,先建 AC 自动机. 套路性的搞个 DP: \(f[i][j]\) 表示前 \(i\) 个字符,当前在 \(AC\) 自动机上的节点是 \(j\) 能匹配到的最多分. 初始化 ...

  9. LibreOj-10012-「一本通-1-2-例-2」Best-Cow-Fences

    题目地址 思路 二分平均值,区间为$0$~$2000$.将每个$a[i]$减去平均值,就只用考虑字段和是否$>=0$了. 关于计算子段和,可以使用前缀和表示,$sum[i]$表示前$i$个数的和 ...

  10. Swagger2配置

    配置类 package top.yalong; import org.springframework.beans.factory.annotation.Value; import org.spring ...