• ABP.vNext系列之Dependency Injection chef


    概念

      ABP.vNext 是一个 ASP.NET Core的开源WEB应用程序框架,关于它的相关介绍可以查看官网(ABP Framework - Open Source Web Application Framework),本系列不过多赘述。

    注入方式

      ABP.vNext 的 Dependency Injection 是基于Microsoft dependency injection extension 库 (Microsoft.Extensions.DependencyInjection)来实现的。由于ABP的核心是模块化设计,每一个模块都定义了自己的服务注册类,所以你需要在你定义的模块中,重写 AbpModule 中的 ConfigureServices 方法。

      ABP.vNext 采用约定配置的方式来实现依赖注入。在默认情况下,某些特定类型已注册到依赖注入容器中了,包括:

    • Module 类默认将默认以 singleton的生命周期进行注入.
    • MVC controllers (继承自Controller or AbpController) 默认将默认以 transient的生命周期进行注入.
    • MVC page models (继承自PageModel or AbpPageModel) 默认将默认以 transient的生命周期进行注入.
    • MVC view components (继承自ViewComponent or AbpViewComponent) 默认将默认以 transient的生命周期进行注入.
    • Application services (继承自ApplicationService 类或其子类) 默认将默认以 transient的生命周期进行注入.
    • Repositories (实现了BasicRepositoryBase 类或其子类) 默认将默认以 transient的生命周期进行注入.
    • Domain services(实现 IDomainService 接口或继承自 DomainService 类) 将默认以 transient的生命周期进行注入.

    ​ 除了以上默认情况下的特定类型会自动注册到DI容器中,你还可以通过实现ITransientDependencyISingletonDependencyIScopedDependency接口来实现自动注入,如以下代码将TaxCalculator注册成为生命周期为transient的服务。

    public class TaxCalculator : ITransientDependency
    {
    }
    

      ABP还提供了 Attribute的方式来实现依赖注入,你可以通过添加 DependencyAttribute 特性来实现,该特性有三个属性

    • Lifetime: 设置声明周期 Singleton, Transient or Scoped.
    • TryRegister: 设置为 true 时表示如果该服务之前未被注册过则注册此服务,如果之前被注册了,这里就不再注册了.
    • ReplaceServices: 设置为 true 将替换之前该服务的注册记录.
    [Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
    public class TaxCalculator
    {
    
    }
    

      需要注意的是,如果使用 DenpendencyAttribute 设置了 Lifetime,其优先级高于其他注入方式。

      当一个服务同时实现了不同的接口时,可以使用 ExposeServicesAttribute 特性来暴露该服务注入时使用的是哪个接口。如果你不指定公开哪个接口,ABP 将采用命名约定的方式进行公开,下面的代码中,ICalculator, ITaxCalculator 就属于默认的命名约定。

    [ExposeServices(typeof(ITaxCalculator))]
    public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransientDependency
    {
    
    }
    

      除了上述的注入方式,ABP.vNext 还保留了手动注册的方式。

    public class BlogModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //Register an instance as singleton
            context.Services.AddSingleton<TaxCalculator>(new TaxCalculator(taxRatio: 0.18));
    
            //Register a factory method that resolves from IServiceProvider
            context.Services.AddScoped<ITaxCalculator>(
                sp => sp.GetRequiredService<TaxCalculator>()
            );
        }
    }
    

      如果需要替换已经存在的服务时,你除了使用 DependencyAttribute 指定 ReplaceServicestrue之外,还可以使用 Microsoft Dependency Injection库中的 IServiceCollection.Replace方法来实现。

    public class MyModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //Replacing the IConnectionStringResolver service
            context.Services.Replace(ServiceDescriptor.Transient<IConnectionStringResolver, MyConnectionStringResolver>());
        }
    }
    

    使用方式

    构造函数注入

    public class TaxAppService : ApplicationService
    {
        private readonly ITaxCalculator _taxCalculator;
    
        public TaxAppService(ITaxCalculator taxCalculator)
        {
            _taxCalculator = taxCalculator;
        }
    
        public void DoSomething()
        {
            //...use _taxCalculator...
        }
    }
    

    属性注入,Asp.NET Core自带的依赖注入并不支持属性注入,ABP.vNext中使用 Autofac来实现。

    public class MyService : ITransientDependency
    {
        public ILogger<MyService> Logger { get; set; }
    
        public MyService()
        {
            Logger = NullLogger<MyService>.Instance;
        }
    
        public void DoSomething()
        {
            //...use Logger to write logs...
        }
    }
    

    通过IServiceProvider获取

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

    ​ 当一个接口被多个实现类实现时,使用时将会获取到最后一个注册的实现类。除非使用 IEnumerable<Interface> 去获取所有的实现类。

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddTransient<IExternalLogger, ElasticsearchExternalLogger>();
        context.Services.AddTransient<IExternalLogger, AzureExternalLogger>();
    }
    
    public class MyService : ITransientDependency
    {
        private readonly IEnumerable<IExternalLogger> _externalLoggers;
    
        public MyService(IEnumerable<IExternalLogger> externalLoggers)
        {
            _externalLoggers = externalLoggers;
        }
    
        public async Task DemoAsync()
        {
            foreach (var externalLogger in _externalLoggers)
            {
                await externalLogger.LogAsync("Example log message...");
            }
        }
    }
    

    ​ 或许某些时候,你需要监听某些服务被注册时的行为,这时候可以使用 IServiceCollection.OnRegistred Event 来实现

    public class AppModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.OnRegistred(ctx =>
            {
                if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true))
                {
                    ctx.Interceptors.TryAdd<MyLogInterceptor>();
                }
            });
        }
    }
    

    集成Autofac

    Asp.NET Core自带的依赖注入容器比较简单,Autofac 是 .Net 最常用的依赖注入框架之一。与 .Net Core 标准 DI 库相比,它提供了一些高级功能,例如动态代理和属性注入。
    为你的项目添加 Volo.Abp.Autofac nuget包,并在你的Module中添加

    using Volo.Abp.Modularity;
    using Volo.Abp.Autofac;
    
    namespace MyCompany.MyProject
    {
        [DependsOn(typeof(AbpAutofacModule))]
        public class MyModule : AbpModule
        {
            //...
        }
    }
    

    最后配置默认DI容器为Autofac

    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!
    }
    
  • 相关阅读:
    OpenStreetMap、googleMap等经纬度和行列号之间相互转化(python,JavaScript,php,Java,C#等)
    利用whoosh对mongoDB的中文文档建立全文检索
    js前端读写文件的方法(json、excel)
    部分网站公开数据的汇总(1)
    部分网站公开数据的汇总(2)
    Buuctf-misc-[BJDCTF 2nd]最简单的misc-y1ng
    Buuctf-web-[SUCTF 2019]CheckIn
    Buuctf-web-[ACTF2020 新生赛]Upload
    Buuctf-web-[ACTF2020 新生赛]BackupFile
    Buuctf-web-[极客大挑战 2019]Upload
  • 原文地址:https://www.cnblogs.com/jesen1315/p/16194762.html
Copyright © 2020-2023  润新知