‹ 首页

abp-dependency-injection

@burakdmir · 收录于 昨天 · 上游提交 2 周前

ABP Framework v10.x (10.4/10.5) dependency injection: ITransientDependency/IScopedDependency/ISingletonDependency, [Dependency], [ExposeServices], LazyServiceProvider, property injection, Autofac. Use when you need service registration, DI, or automatic registration in ABP.

适合你,如果正在用 ABP Framework 并需要处理依赖注入

/ 通过 npx 安装 校验哈希
npx oh-my-skill add burakdmir/abp-skills/abp-dependency-injection
/ 通过 bash 安装
curl -fsSL https://oh-my-skill.com/install.sh | bash -s -- burakdmir/abp-skills/abp-dependency-injection
/ 已经装过?验证本机副本,不用重装
npx oh-my-skill verify burakdmir/abp-skills/abp-dependency-injection
安装目标可用 --agent / --scope 或 --to 明确指定;省略时只会在唯一已存在的 agent 目录上自动选择,零命中或多命中会停止并提示。content_hash 缺失或不一致均拒装。
13GitHub stars
~1.5K上下文体积 · 单文件
索引托管

怎么用

商店整理自技能原文 · 版本 ce71259 · 表述以原文为准
它做什么

安装后,Claude 能回答 ABP Framework 依赖注入的问题,包括自动注册、生命周期接口、[Dependency] 和 [ExposeServices] 特性、属性注入、Autofac 集成、延迟解析等。它会解释概念、提供代码示例,并给出最佳实践。

什么时候触发

当你询问 ABP 框架中的依赖注入、服务注册、ITransientDependency 等生命周期接口、[Dependency] 或 [ExposeServices] 特性、Autofac 相关话题时触发。

装好后可以这样说
展示如何只暴露指定接口,不暴露其他实现接口。
技能原文 SKILL.md作者撰写 · MIT · ce71259

ABP Dependency Injection Skill

Trigger

User asks about dependency injection, DI, ITransientDependency, ISingletonDependency, IScopedDependency, [Dependency] attribute, [ExposeServices] attribute, auto service registration, or Autofac in ABP Framework.


Core Concepts

ABP's DI system is built on Microsoft's Microsoft.Extensions.DependencyInjection with:

  • Conventional (automatic) registration — Classes registered by convention
  • Dependency interfacesITransientDependency, ISingletonDependency, IScopedDependency
  • Dependency attribute[Dependency] for fine-grained control
  • ExposeServices attribute[ExposeServices] to control exposed interfaces
  • Autofac integration — Required for dynamic proxying (included in startup templates)

Conventional Registration

ABP automatically registers all services in your assembly. No manual registration needed.

// This class is auto-registered as transient
public class TaxCalculator : ITransientDependency
{
    public decimal Calculate(TaxInput input) { ... }
}
Disable Auto Registration
public class BlogModule : AbpModule
{
    public BlogModule()
    {
        SkipAutoServiceRegistration = true;
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        // Manual registration
        context.Services.AddAssemblyOf<BlogModule>();
    }
}

Dependency Interfaces

Implement these interfaces for automatic registration:

| Interface | Lifetime | Use Case | |---|---|---| | ITransientDependency | Transient | Default for most services | | ISingletonDependency | Singleton | Shared state, caches | | IScopedDependency | Scoped | Per-request state |

public class TaxCalculator : ITransientDependency { }
public class CacheService : ISingletonDependency { }
public class RequestTracker : IScopedDependency { }

Dependency Attribute

More control over registration:

[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class TaxCalculator
{
}
Properties

| Property | Type | Purpose | |---|---|---| | Lifetime | ServiceLifetime | Transient, Singleton, or Scoped | | TryRegister | bool | Register only if not already registered | | ReplaceServices | bool | Replace existing registration |

[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class MyCacheService { }

[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class OverridingService { }
[Dependency] has higher priority than dependency interfaces if Lifetime is defined.

ExposeServices Attribute

Control which interfaces a class exposes:

[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ICalculator, ITaxCalculator, ICanCalculate, ITransientDependency
{
}
  • Only ITaxCalculator can be injected
  • TaxCalculator, ICalculator, ICanCalculate are NOT injectable
Expose Multiple Services
[ExposeServices(typeof(ITaxCalculator), typeof(ICalculator))]
public class TaxCalculator : ICalculator, ITaxCalculator, ITransientDependency
{
}
Expose All (default behavior)

Without [ExposeServices], all implemented interfaces are exposed:

public class TaxCalculator : ICalculator, ITaxCalculator, ITransientDependency
{
}
// Can inject: TaxCalculator, ICalculator, ITaxCalculator

Combining Attributes and Interfaces
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ITaxCalculator, ITransientDependency
{
}
  • ReplaceServices = true → replaces existing ITaxCalculator registration
  • ExposeServices → only ITaxCalculator can be injected
  • ITransientDependency → transient lifetime (overridden by [Dependency] if specified)

Inherently Registered Types

These types are automatically registered by ABP:

  • AbpModule implementations
  • Controllers, PageModels
  • Domain services, Application services
  • Repositories (via EF Core / MongoDB modules)

Autofac Integration

ABP requires a DI provider that supports dynamic proxying for:

  • Unit of Work interception
  • Validation interception
  • Authorization interception
  • Auditing interception
  • Feature checking

Startup templates come with Autofac pre-installed.

Manual Autofac Setup
dotnet add package Volo.Abp.Autofac
[DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule { }

In Program.cs:

builder.Host.UseAutofac();

Property Injection

ABP supports property injection via Autofac:

public class MyService : ITransientDependency
{
    public IEmailSender EmailSender { get; set; } // Property injected

    private readonly IRepository<MyEntity> _repository; // Constructor injected

    public MyService(IRepository<MyEntity> repository)
    {
        _repository = repository;
    }
}
Constructor injection is preferred. Property injection is useful for optional dependencies.

Resolving Services
Constructor Injection (Recommended)
public class MyService : ITransientDependency
{
    private readonly IEmailSender _emailSender;

    public MyService(IEmailSender emailSender)
    {
        _emailSender = emailSender;
    }
}
Property Injection
public class MyService : ITransientDependency
{
    public IEmailSender EmailSender { get; set; }
}
Manual Resolution (Avoid When Possible)
public class MyService : ITransientDependency
{
    private readonly IServiceProvider _serviceProvider;

    public MyService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void DoWork()
    {
        var emailSender = _serviceProvider.GetRequiredService<IEmailSender>();
    }
}
Lazy Service Resolution (LazyServiceProvider)

Instead of manual resolution via IServiceProvider, ABP's lazy service resolution is preferred. ABP base classes (ApplicationService, DomainService, AbpController) come with a LazyServiceProvider property out of the box — it prevents constructor bloat when you have optional or numerous dependencies:

public class BookAppService : ApplicationService
{
    // No need to inject — comes from the base class
    private IEmailSender EmailSender => LazyServiceProvider.LazyGetRequiredService<IEmailSender>();

    public async Task NotifyAsync()
    {
        await EmailSender.SendAsync("to@x.com", "Subject", "Body");
    }
}

In non-base-class services, inject ITransientCachedServiceProvider (the old IAbpLazyServiceProvider is for backward compatibility and may be removed in the future):

public class MyService : ITransientDependency
{
    private readonly ITransientCachedServiceProvider _serviceProvider;
    public MyService(ITransientCachedServiceProvider serviceProvider)
        => _serviceProvider = serviceProvider;

    private IEmailSender EmailSender => _serviceProvider.GetRequiredService<IEmailSender>();
}

Best Practices
  1. Use conventional registration — implement ITransientDependency (default)
  2. Prefer constructor injection — explicit dependencies, easier to test
  3. Use [Dependency(ReplaceServices = true)] to override framework services
  4. Use [ExposeServices] to limit exposed interfaces
  5. Use IScopedDependency for per-request state (HTTP context, etc.)
  6. Use ISingletonDependency only for stateless services or caches
  7. Don't use service locator pattern — avoid IServiceProvider resolution
  8. Keep services focused — single responsibility, small interfaces
  9. Use Autofac — required for dynamic proxying (interceptors, UOW, validation)
  10. Skip auto-registration only when you need full control over DI setup

Common Patterns
Repository Injection
public class BookAppService : ApplicationService, IBookAppService
{
    private readonly IRepository<Book, Guid> _bookRepository;

    public BookAppService(IRepository<Book, Guid> bookRepository)
    {
        _bookRepository = bookRepository;
    }
}
Domain Service
public class BookManager : DomainService, ITransientDependency
{
    private readonly IRepository<Book, Guid> _bookRepository;

    public BookManager(IRepository<Book, Guid> bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public async Task<Book> CreateAsync(CreateBookDto input)
    {
        var book = new Book { Name = input.Name };
        return await _bookRepository.InsertAsync(book);
    }
}
Override Framework Service
[Dependency(ReplaceServices = true)]
public class MyCustomEmailSender : IEmailSender, ITransientDependency
{
    public async Task SendAsync(string to, string subject, string body)
    {
        // Custom email logic
    }
}

Related
  • [Framework Core](../abp-framework/SKILL.md) — base classes, module system, configuration
  • [Modularity](../abp-modularity/SKILL.md) — module-based DI registration, [DependsOn]
  • [DDD](../abp-ddd/SKILL.md) — application/domain service registration
  • Autofac — DI container with dynamic proxying support
  • ABP Docs: https://abp.io/docs/latest/framework/fundamentals/dependency-injection
按 MIT 许可原样转载,未经改动 · 在 GitHub 查看 →

评论

登录即可评论;带「已验证安装」的,是发布者名下有本店的安装或持有记录。