文章目录

介绍

ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的。所以我们采用dotnet自带的注入方式也是支持的

  • 由于ABP是一个模块化框架,因此每个模块都定义它自己的服务并在它自己的单独模块类中通过依赖注入进行注册.例:
public class BlogModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//在此处注入依赖项
// dotnet自带依赖注入方式也是支持的
context.services.AddTransient
context.services.AddScoped
context.services.AddSingleton
}
}

Autofac

Autofac 是.Net世界中最常用的依赖注入框架之一. 相比.Net Core标准的依赖注入库, 它提供了更多高级特性, 比如动态代理和属性注入.

集成

1.安装 Volo.Abp.Autofac nuget 包到你的项目 (对于一个多项目应用程序, 建议安装到可执行项目或者Web项目中.)

2.模块添加 AbpAutofacModule 依赖:

    [DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule
{
//...
}
}

3.配置 AbpApplicationCreationOptions 用 Autofac 替换默认的依赖注入服务. 根据应用程序类型, 情况有所不同

  • ASP.NET Core 应用程序
public class Program
{
public static int Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} internal static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac(); //Integrate Autofac!
}
  • 控制台应用程序
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); //Autofac integration
}))
{
//...
}
}
}
}

依照约定的注册

如果实现这些接口,则会自动将类注册到依赖注入:

  • ITransientDependency 注册为transient生命周期.
  • ISingletonDependency 注册为singleton生命周期.
  • IScopedDependency 注册为scoped生命周期.

默认特定类型

一些特定类型会默认注册到依赖注入.例子:

  • 模块类注册为singleton.
  • MVC控制器(继承Controller或AbpController)被注册为transient.
  • MVC页面模型(继承PageModel或AbpPageModel)被注册为transient.
  • MVC视图组件(继承ViewComponent或AbpViewComponent)被注册为transient.
  • 应用程序服务(实现IApplicationService接口或继承ApplicationService类)注册为transient.
  • 存储库(实现IRepository接口)注册为transient.
  • 域服务(实现IDomainService接口)注册为transient.

手动注册

在某些情况下,你可能需要向IServiceCollection手动注册服务,尤其是在需要使用自定义工厂方法或singleton实例时.在这种情况下,你可以像Microsoft文档描述的那样直接添加服务.

public class BlogModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.services.AddTransient<ITestMicrosoftManager, TestMicrosoftManager>();
}
}

如何使用

构造函数注入

  • 构造方法注入是将依赖项注入类的首选方式

属性注入

  • Microsoft依赖注入库不支持属性注入.但是,ABP可以与第三方DI提供商(例如Autofac)集成,以实现属性注入。
  • 属性注入依赖项通常被视为可选依赖项.这意味着没有它们,服务也可以正常工作.Logger就是这样的依赖项,MyService可以继续工作而无需日志记录.
public class MyService : ITransientDependency
{
public ILogger<MyService> Logger { get; set; } public MyService()
{
Logger = NullLogger<MyService>.Instance;
} public void DoSomething()
{
//...使用 Logger 写日志...
}
}

IServiceProvider

直接从IServiceProvider解析服务.在这种情况下,你可以将IServiceProvider注入到你的类并使用

public class MyService : ITransientDependency
{
private readonly IServiceProvider _serviceProvider; public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
} public void DoSomething()
{
var taxCalculator = _serviceProvider.GetService<ITaxCalculator>();
//...
}
}

服务替换

在某些情况下,需要替换某些接口的实现.

  • ITestManager有一个默认实现DefaultManager,但是我现在想替换成TestReplaceManager,该如何操作呢?

原生dotnet方式替换

services.Replace(ServiceDescriptor.Transient<ITestManager, TestReplaceManager>());

Abp支持

  • 加上Dependency特性标签
  • 加上ExposeServices特性标签
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITestManager))]
public class TestReplaceManager : ITestManager, ITransientDependency
{
public void Print()
{
Console.WriteLine("TestReplaceManager");
}
}

问题

  1. 有时候我们实现了ITransientDependency,ISingletonDependency,IScopedDependency但是再运行是还是提示依赖注入失败?
  • 实现类的名称拼写错误
  • 比如接口名称为ITestAppService,但是实现类为DefaultTessAppService,这个时候编译不会报错,但是运行报错,下面会基于源码分析。
public class DefaultTessAppService : ApplicationService, ITestAppService
{
// ....
}
  1. 我通过[Dependency(ReplaceServices = true)]替换服务没有生效?
  • 请添加[ExposeServices(typeof(ITestManager))]显示暴露服务,下面会基于源码分析。

源码分析

  1. 进入到Startup.AddApplication源码
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<xxxManagementHttpApiHostModule>();
}
}
  1. 进入到await app.ConfigureServicesAsync()源码
public async static Task<IAbpApplicationWithExternalServiceProvider> CreateAsync(
[NotNull] Type startupModuleType,
[NotNull] IServiceCollection services,
Action<AbpApplicationCreationOptions>? optionsAction = null)
{
var app = new AbpApplicationWithExternalServiceProvider(startupModuleType, services, options =>
{
options.SkipConfigureServices = true;
optionsAction?.Invoke(options);
}); await app.ConfigureServicesAsync();
return app;
}
  1. 主要查看ConfigureServices下的Services.AddAssembly(assembly)方法。
 public virtual async Task ConfigureServicesAsync()
{ // 省略... var assemblies = new HashSet<Assembly>(); //ConfigureServices
foreach (var module in Modules)
{
if (module.Instance is AbpModule abpModule)
{
if (!abpModule.SkipAutoServiceRegistration)
{
var assembly = module.Type.Assembly;
if (!assemblies.Contains(assembly))
{
Services.AddAssembly(assembly);
assemblies.Add(assembly);
}
}
} try
{
await module.Instance.ConfigureServicesAsync(context);
}
catch (Exception ex)
{
throw new AbpInitializationException($"An error occurred during {nameof(IAbpModule.ConfigureServicesAsync)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex);
}
} // 省略...
}

4.进入下面AddAssembly下AddType的逻辑

public class DefaultConventionalRegistrar : ConventionalRegistrarBase
{
public override void AddType(IServiceCollection services, Type type)
{
if (IsConventionalRegistrationDisabled(type))
{
return;
}
// 查看是否有DependencyAttribute特性标签
var dependencyAttribute = GetDependencyAttributeOrNull(type);
// 判断是否有实现接口,注入对于的类型。
var lifeTime = GetLifeTimeOrNull(type, dependencyAttribute); if (lifeTime == null)
{
return;
} var exposedServiceTypes = GetExposedServiceTypes(type); TriggerServiceExposing(services, type, exposedServiceTypes); foreach (var exposedServiceType in exposedServiceTypes)
{
var serviceDescriptor = CreateServiceDescriptor(
type,
exposedServiceType,
exposedServiceTypes,
lifeTime.Value
); if (dependencyAttribute?.ReplaceServices == true)
{
services.Replace(serviceDescriptor);
}
else if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
else
{
services.Add(serviceDescriptor);
}
}
}
} // GetLifeTimeOrNull protected virtual ServiceLifetime? GetLifeTimeOrNull(Type type, DependencyAttribute? dependencyAttribute)
{
return dependencyAttribute?.Lifetime ?? GetServiceLifetimeFromClassHierarchy(type) ?? GetDefaultLifeTimeOrNull(type);
}
// abp 三个生命周期
protected virtual ServiceLifetime? GetServiceLifetimeFromClassHierarchy(Type type)
{
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Transient;
} if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Singleton;
} if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Scoped;
} return null;
}

5.重点到了,看下为什么名称错误为什么导致注入失败。

  • 通过接口的名称去获取实现。
  • 也能解释有时候不显示指定ExposeServices可能替换失败的问题
public class ExposeServicesAttribute : Attribute, IExposedServiceTypesProvider
{
// 省略... private static List<Type> GetDefaultServices(Type type)
{
var serviceTypes = new List<Type>(); foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{
var interfaceName = interfaceType.Name;
if (interfaceType.IsGenericType)
{
interfaceName = interfaceType.Name.Left(interfaceType.Name.IndexOf('`'));
} // 查询到实现类的名称是否是移除I
if (interfaceName.StartsWith("I"))
{
interfaceName = interfaceName.Right(interfaceName.Length - 1);
}
// 查询到实现类的名称是否以接口名结尾
if (type.Name.EndsWith(interfaceName))
{
serviceTypes.Add(interfaceType);
}
} return serviceTypes;
}
}

Abp vNext Pro

如果觉得可以,不要吝啬你的小星星哦

文章目录

Abp vNext 依赖注入的更多相关文章

  1. ABP的依赖注入

    目录 说说ABP的依赖注入 代码追踪 说说ABP的依赖注入 上篇abp运行机制分析分析了ABP在启动时,都做了那些事:这篇我们来说说ABP的最核心的一部分:依赖注入(DependencyInjecti ...

  2. ABP vNext 自动注入,暗藏天坑如斯

    导言 我们在使用ABP vNext框架时,都知道该框架为我们实现了自动依赖注入(实现自动注入需要在项目里面创建Module类,并且将Module类上的DependsOn到相应的启动Module类或调用 ...

  3. ABP框架 - 依赖注入

    文档目录 本节内容: 什么是依赖注入 传统方式的问题 解决方案 构造器注入模式 属性注入模式 依赖注入框架 ABP 依赖注入基础 注册依赖 约定注入 辅助接口 自定义/直接 注册 使用IocManag ...

  4. ABP之依赖注入

    写在开头 ABP开源项目最近有点小火,还开展了线下活动.本着学习DDD的心态与学习开源代码的的好奇,我也看了一遍ABP源码,在此将自己学习ABP的一些心得记录下来. 作为核心的IoC 作为一种解耦的方 ...

  5. (译)ABP之依赖注入

    原文地址:https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection 什么是依赖注入 传统方式的问题 解决方案 构造函数注入 ...

  6. Asp.Net Core 3.1 Api 集成Abp项目依赖注入

    Abp 框架 地址https://aspnetboilerplate.com/ 我们下面来看如何在自己的项目中集成abp的功能 我们新建core 3.1 API项目和一个core类库 然后 两个项目都 ...

  7. 3. abp依赖注入的分析.md

    abp依赖注入的原理剖析 请先移步参考 [Abp vNext 源码分析] - 3. 依赖注入与拦截器 本文此篇文章的补充和完善. abp的依赖注入最后是通过IConventionalRegister接 ...

  8. ABP vNext系列文章03---依赖注入

    一.依赖注入的类型注册 ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的.因此,它的 ...

  9. ABP(现代ASP.NET样板开发框架)系列之6、ABP依赖注入

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...

  10. ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

随机推荐

  1. python 爬虫某东网商品信息 | 没想到销量最高的是

    哈喽大家好,我是咸鱼 好久没更新 python 爬虫相关的文章了,今天我们使用 selenium 模块来简单写个爬虫程序--爬取某东网商品信息 网址链接:https://www.jd.com/ 完整源 ...

  2. 自然语言处理 Paddle NLP - 预训练语言模型及应用

    什么是语言理解? 关于疫情的一段对话: 中国:我们这边快完了 欧洲:我们这边快完了 中国:我们好多了 欧洲:我们好多了 挑战: 语言的复杂性和多样性 多义/同义/歧义现象 灵活多变的表达形式 语言背后 ...

  3. 【Rust-book】第五章 使用结构体来组织相关联的数据

    第五章 使用结构体来组织相关联的数据 结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体. 可以把结构体视作对象中的数据属性 1 对比元组和结构体之间的异同 ...

  4. 发布:iNeuOS工业互联网操作系统 V5 Preview1 版本(自主可控)

    这半年来一直深耕包头,这个城市比较不错,但是推进项目的难度确实挺大的.与开发产品相比,后者更省心.但是光研发产品,没有项目依托,没办法产生价值.有些大学和研究院确实有好的产品,但是没有市场化能力,再好 ...

  5. 一篇随笔学会CSS

    CSS3 1.CSS介绍 HTML+CSS+JS 结构+表现+交互 2.CSS发展史 Cascading Style Sheet 层叠级联样式表 表现层:美化网页(字体.颜色.边距.宽高.网页定位.网 ...

  6. 采集douban

    # -*- coding: utf-8 -*-"""Created on Thu Oct 31 16:14:02 2019 @author: DELL"&quo ...

  7. matlab2014a破解不完全,报错Test checkout of feature 'Compiler' failed

    解决方案 报错情况: 目标是把.m文件转化为.exe文件,先运行 mcc -m 你的文件.m 如果报错 Test checkout of feature 'Compiler' failed 是因为你的 ...

  8. 带你掌握利用Terraform不同数据源扩展应用场景

    本文分享自华为云社区<利用Terraform不同数据源扩展应用场景>,作者: kaliarch . 一 背景 在生产环境中使用Terraform进行基础设施编排,通常又一些信息是通过其他外 ...

  9. 你的Spring应用启动很慢?不妨试试这个工具!

    睡不着闲逛,在GitHub上看到一个挺实用的开源项目:Spring Startup Analyzer. 从项目名称中就大概能猜到,这是一个分析Spring应用启动过程的工具.Spring Startu ...

  10. 学好Linux的必经之路

    学好Linux的必经之路 学习动机的培养对于一个人学习习惯的形成有着重要的作用.当我们在学习某一个事物时,建立属于我们自己的学习方法,以此培养我们学习Linux系统的学习动机. 当前,Linux系统属 ...