Abp vNext 依赖注入
介绍
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");
}
}
问题
- 有时候我们实现了ITransientDependency,ISingletonDependency,IScopedDependency但是再运行是还是提示依赖注入失败?
- 实现类的名称拼写错误
- 比如接口名称为ITestAppService,但是实现类为DefaultTessAppService,这个时候编译不会报错,但是运行报错,下面会基于源码分析。
public class DefaultTessAppService : ApplicationService, ITestAppService
{
// ....
}
- 我通过[Dependency(ReplaceServices = true)]替换服务没有生效?
- 请添加[ExposeServices(typeof(ITestManager))]显示暴露服务,下面会基于源码分析。
源码分析
- 进入到Startup.AddApplication源码
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<xxxManagementHttpApiHostModule>();
}
}
- 进入到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;
}
- 主要查看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 Pro Github地址 的 Vue3 实现版本 开箱即用的中后台前端/设计解决方案.
- 文档地址
- 演示地址:用户名admin 密码1q2w3E*
- Abp Vnext Pro Suite Github地址 代码生成器。
- 演示地址:用户名admin 密码1q2w3E*
- 视频教程
如果觉得可以,不要吝啬你的小星星哦
Abp vNext 依赖注入的更多相关文章
- ABP的依赖注入
目录 说说ABP的依赖注入 代码追踪 说说ABP的依赖注入 上篇abp运行机制分析分析了ABP在启动时,都做了那些事:这篇我们来说说ABP的最核心的一部分:依赖注入(DependencyInjecti ...
- ABP vNext 自动注入,暗藏天坑如斯
导言 我们在使用ABP vNext框架时,都知道该框架为我们实现了自动依赖注入(实现自动注入需要在项目里面创建Module类,并且将Module类上的DependsOn到相应的启动Module类或调用 ...
- ABP框架 - 依赖注入
文档目录 本节内容: 什么是依赖注入 传统方式的问题 解决方案 构造器注入模式 属性注入模式 依赖注入框架 ABP 依赖注入基础 注册依赖 约定注入 辅助接口 自定义/直接 注册 使用IocManag ...
- ABP之依赖注入
写在开头 ABP开源项目最近有点小火,还开展了线下活动.本着学习DDD的心态与学习开源代码的的好奇,我也看了一遍ABP源码,在此将自己学习ABP的一些心得记录下来. 作为核心的IoC 作为一种解耦的方 ...
- (译)ABP之依赖注入
原文地址:https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection 什么是依赖注入 传统方式的问题 解决方案 构造函数注入 ...
- Asp.Net Core 3.1 Api 集成Abp项目依赖注入
Abp 框架 地址https://aspnetboilerplate.com/ 我们下面来看如何在自己的项目中集成abp的功能 我们新建core 3.1 API项目和一个core类库 然后 两个项目都 ...
- 3. abp依赖注入的分析.md
abp依赖注入的原理剖析 请先移步参考 [Abp vNext 源码分析] - 3. 依赖注入与拦截器 本文此篇文章的补充和完善. abp的依赖注入最后是通过IConventionalRegister接 ...
- ABP vNext系列文章03---依赖注入
一.依赖注入的类型注册 ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的.因此,它的 ...
- ABP(现代ASP.NET样板开发框架)系列之6、ABP依赖注入
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- ABP源码分析六:依赖注入的实现
ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...
随机推荐
- 混合编程python与C++
上个版本: 只是用到ctypes进行传输, 这次将python服务端更改为C++服务端,方便后续维护. 本文实现功能: python传输图片给C++, C++接受图片后对图片进行处理,并将结果返回给p ...
- 基于.NetCore开发博客项目 StarBlog - (29) 开发RSS订阅功能
前言 最近忙中偷闲把博客的评论功能给做完了,我可以说这个评论功能已经达到「精致」的程度了 但在正式发布之前,先卖个关子,来介绍一下另一个新功能--RSS订阅 RSS是啥 来自hk gov新闻网的介绍~ ...
- .Net下验证MongoDB 的 Linq 模式联合查询是否可用
MongoDB.Driver 类库提供了 Linq 查询的支持.然而,在使用 Linq 进行联合查询时,是否能够正确转换为 MongoDB 底层的查询语句还有待验证.今天,我将进行实验来验证一下. 输 ...
- Day04_Java_作业
A:选择题 1.下列哪个答案与show不是方法重载(b ). class Demo { void show(int a,int b,float c){} } A.void show(int a,flo ...
- postgresql + timescaledb离线安装笔记(zabbix数据库准备工作)
实验环境 操作系统:centos 7.6 PostgreSQL:14.6 timescaledb:2.8.1 网络:本地无网络 1 编译源码安装 1.1 准备工作 useradd postgres m ...
- 浅谈php伪协议的运用
浅谈php伪协议的运用 (133条消息) PHP Filter伪协议Trick总结_php伪协议rot13的用法_swtre33的博客-CSDN博客 php死亡exit()绕过 - xiaolong' ...
- CentOS系统修改yum源
看了一下自己之前写的文章,写的那叫一个垃圾.无地自容.作为一个菜鸡.现在不妨在博客上记录一下自己学习的记录,同时发表出来,也算作是对自己的勉励. 吾辈不孤,吾道不寡,诸君加油! 下面进入正题: Cen ...
- Linux 过滤进程和端口号
IDEA覆盖率测速显示百分比 ctrl + alt + F6 取消勾选 ps - ef | grep java过滤Java进程 netstat -anop | grep 74933 过滤端口号 重命名 ...
- 3.你不知道的go语言控制语句
目录 本篇前瞻 Leetcode习题9 题目描述 题目分析 代码编写 知识点归纳 控制结构 顺序结构(Sequence) 声明和赋值 算术运算符 位运算符 逻辑运算 分支结构 if 语句 switch ...
- 行行AI人才直播第17期:无界AI联合创始人马千里《AIGC,比生产力还多》
谁也没有想到,短短几个月内,AI就在各行各业掀起了一阵狂风暴雨.ChatGPT.Stable Diffusion.Midjourney--AI已经变得十八般武艺样样精通,不仅能够高效率完成很多日常工作 ...