在.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. 第3.3节 强大的Python列表

    一. 列表切片操作补充 列表切片支持所有序列切片的方法,以倒序切片和步长大于1的情况再举例验证一下: l=[1,2,3,4,5] l[::2] #结果[1, 3, 5] l[-1::2] #结果[5] ...

  2. 第11.17节 Python 正则表达式扩展功能:命名组功能及组的反向引用

    一. 引言 在<第11.16节 Python正则元字符"()"(小括号)与组(group)匹配模式>介绍了组匹配模式,在一个正则表达式内可以定义多个组,每个组都有一个顺 ...

  3. [GKCTF2020]CheckIN 注意了解多方面的东西

    打开之后是这样的,没有发现反序列化函数,但是发现有一个@eval,想到了一句话,这是用base64进行传参首先传参phpinfo();看看,需要经过base64编码 http://e0cc90ac-d ...

  4. [极客大挑战 2019]HardSQL updatexml报错注入小结

    报错注入链接: https://www.cnblogs.com/richardlee97/p/10617115.html报错原因: 其原因主要是因为虚拟表的主键重复.按照MySQL的官方说法,grou ...

  5. JDBC(一)—— JDBC概述

    Jdbc概述 Java DataBase connectivity(Java语言连接数据库) Jdbc本质是什么? 是Sun公司制定的一套接口,java.sql.* 接口都有调用者和实现者 面向接口调 ...

  6. Apriori 算法-如何进行关联规则挖掘

    公号:码农充电站pro 主页:https://codeshellme.github.io 在数据分析领域有一个经典的故事,叫做"尿布与啤酒". 据说,在美国西部的一家连锁超市发现, ...

  7. 题解-CF1437F Emotional Fishermen

    题面 CF1437F Emotional Fishermen 给 \(n\) 个数的序列 \(a_i\),求有多少种 \(n\) 个数的排列 \(p_i\),使得 \[\frac{a_{p_i}}{\ ...

  8. Codeforces Edu Round 53 A-D

    A. Diverse Substring 找普遍性(特殊解即可). 最简单的便是存在一个区间\([i, i + 1] (1 <= i < n)\),且$str[i] $ $ != str[ ...

  9. 题解-Enemy is weak

    Enemy is weak 求序列 \(a\{n\}\) 中的三元逆序对数量. 数据范围:\(3\le n\le 1e6\). 这题真是一道又好又水的题,可是我看别人的题解做法真是玄学难懂,于是蒟蒻要 ...

  10. 关于svg格式问题

    背景介绍: 在使用photoswipe的时候,引入了css,按钮是使用svg进行展示的,在用vs2010开发调试过程中,发现不能显示按钮.在请求.svg 的文件时,响应头中的content Type始 ...