| name | abp-dependency-injection |
| description | 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 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.
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)
{
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
{
}
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; }
private readonly IRepository<MyEntity> _repository;
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
{
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
IScopedDependency for per-request state (HTTP context, etc.)
- Use
ISingletonDependency only for stateless services or caches
- Don't use service locator pattern — avoid
IServiceProvider resolution
- 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)
{
}
}
Related