Abp vNext 依赖注入

这篇具有很好参考价值的文章主要介绍了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");
	}
}

问题

  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 Pro Github地址 的 Vue3 实现版本 开箱即用的中后台前端/设计解决方案.
  • 文档地址
  • 演示地址:用户名admin 密码1q2w3E*
  • Abp Vnext Pro Suite Github地址 代码生成器。
  • 演示地址:用户名admin 密码1q2w3E*
  • 视频教程

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

文章目录文章来源地址https://www.toymoban.com/news/detail-710350.html

到了这里,关于Abp vNext 依赖注入的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Abp vNext(三)数据迁移

    文档版本:7.0 官方文档给的数据迁移的方式是这样的, 第一步 在 Acme.BookStore.EntityFrameworkCore 目录打开命令行终端输入以下命令: 第二步 运行 Acme.BookStore.DbMigrator 应用程序来更新数据库 用上面方式,初始化数据库、增加字段以及删除字段,试了之后都没问题,可正常执行。

    2024年01月18日
    浏览(36)
  • 迁移现有用户数据到ABP vNext

    使用 ABP vNext(下文简称 ABP)时,通常都是从 cli 开始新建模板,从一个空项目开始。对已经存续的项目来说,现有的数据,特别是用户等核心数据需要进行迁移。 老的项目,随着规模越来越大,每次修改都需要更改非常多地方,最重要的是,共用数据库使得维护起来需要小

    2024年02月09日
    浏览(41)
  • Abp Vnext 搭建 ELK日志记录

    ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana 安装 Elasticsearch Kibana 的方法我前面文章有写 Abp中加入Logstash Kibana 查看日志 kibana新建索引 logstash-* 然后点击下一步即可 我这边是已经创建完毕了 查看日志 这样咱们就完成ELK 的初步搭建和 后续学习 ES ,因为一个

    2024年02月08日
    浏览(34)
  • OData WebAPI实践-与ABP vNext集成

    本文属于 OData 系列文章 ABP 是一个流行的 ASP. NET 开发框架,旧版的的 ABP 已经能够非常好的支持了 OData ,并提供了对应的 OData 包。 ABP vNext 是一个重新设计的,面向微服务的框架,提供了一些非常有用的特性,包括分页查询等但是它并不能原生支持 OData ,我们需要自行实现

    2024年02月04日
    浏览(37)
  • Abp Vnext 动态(静态)API客户端源码解析

    根据以往的经验,通过接口远程调用服务的原理大致如下: 服务端:根据接口定义方法的签名生成路由,并暴露Api。 客户端:根据接口定义方法的签名生成请求,通过HTTPClient调用。 这种经验可以用来理解ABP VNext自动API的方式,但如果不使用自动API并且控制器定义了路由的情

    2024年02月06日
    浏览(56)
  • abp Vnext OpenIddect 扩展微信小程序授权登录

    abp vnext6.0之后官方替换了原来的ids4,采用了openIddict的oauth认证框架。使用之前的方法已经不行,以下是OpenIddect 使用ITokenExtensionGrant接口进行的授权登入扩展,按照以下代码可实现,欢迎交流指正。 使用上面定义的ExtensionGrantName扩展的这个openiddict的认证流程的名字 钉钉可参

    2024年02月10日
    浏览(28)
  • Go 项目依赖注入wire工具最佳实践介绍与使用

    目录 一、引入 二、控制反转与依赖注入 三、为什么需要依赖注入工具 3.1 示例 3.2 依赖注入写法与非依赖注入写法 四、wire 工具介绍与安装 4.1 wire 基本介绍 4.2 安装 五、Wire 的基本使用 5.1 前置代码准备 5.2 使用 Wire 工具生成代码 六、Wire 核心技术 5.1 抽象语法树分析 5.2 模板

    2024年04月08日
    浏览(43)
  • Angular:动态依赖注入和静态依赖注入

    问题描述: 自己写的服务依赖注入到组件时候是直接在构造器内初始化的。 直到看见代码中某大哥写的 private injector: Injector   在 Angular 中,使用构造函数注入的方式将服务注入到组件中是一种静态依赖注入的方式。这种方式需要在组件的构造函数中显式声明该服务的类型,

    2024年02月15日
    浏览(48)
  • Spring IOC:详解【依赖注入数值问题 & 依赖注入方式】

    编译软件:IntelliJ IDEA 2019.2.4 x64 操作系统:win10 x64 位 家庭版 Maven版本:apache-maven-3.6.3 Mybatis版本:3.5.6 spring版本:5.3.1 第一章:初识Spring:如何在Maven工程上搭建Spring框架? 第二章:Spring IOC:IOC在Spring底层中如何实现? 第三章:Spring IOC:详解【依赖注入数值问题 依赖注入

    2024年02月04日
    浏览(49)
  • Spring DI简介及依赖注入方式和依赖注入类型

    目录 一、什么是依赖注入 二、依赖注入方式 1. Setter注入 2. 构造方法注入 3. 自动注入  三、依赖注入类型 1. 注入bean类型 2. 注入基本数据类型 3. 注入List集合 4. 注入Set集合 5. 注入Map集合 6. 注入Properties对象 往期专栏文章相关导读  1. Maven系列专栏文章 2. Mybatis系列专栏文章

    2024年02月02日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包