abp-dependency-injection
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 oh-my-skill add burakdmir/abp-skills/abp-dependency-injectioncurl -fsSL https://oh-my-skill.com/install.sh | bash -s -- burakdmir/abp-skills/abp-dependency-injectionnpx oh-my-skill verify burakdmir/abp-skills/abp-dependency-injection怎么用
商店整理自技能原文 · 版本 ce71259 · 表述以原文为准安装后,Claude 能回答 ABP Framework 依赖注入的问题,包括自动注册、生命周期接口、[Dependency] 和 [ExposeServices] 特性、属性注入、Autofac 集成、延迟解析等。它会解释概念、提供代码示例,并给出最佳实践。
当你询问 ABP 框架中的依赖注入、服务注册、ITransientDependency 等生命周期接口、[Dependency] 或 [ExposeServices] 特性、Autofac 相关话题时触发。
技能原文 SKILL.md
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 interfaces —
ITransientDependency,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 ifLifetimeis defined.
ExposeServices Attribute
Control which interfaces a class exposes:
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ICalculator, ITaxCalculator, ICanCalculate, ITransientDependency
{
}
- Only
ITaxCalculatorcan be injected TaxCalculator,ICalculator,ICanCalculateare 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 existingITaxCalculatorregistrationExposeServices→ onlyITaxCalculatorcan be injectedITransientDependency→ transient lifetime (overridden by[Dependency]if specified)
Inherently Registered Types
These types are automatically registered by ABP:
AbpModuleimplementations- 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
- Use conventional registration — implement
ITransientDependency(default) - Prefer constructor injection — explicit dependencies, easier to test
- Use
[Dependency(ReplaceServices = true)]to override framework services - Use
[ExposeServices]to limit exposed interfaces - Use
IScopedDependencyfor per-request state (HTTP context, etc.) - Use
ISingletonDependencyonly for stateless services or caches - Don't use service locator pattern — avoid
IServiceProviderresolution - Keep services focused — single responsibility, small interfaces
- Use Autofac — required for dynamic proxying (interceptors, UOW, validation)
- 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