Help us improve
Share bugs, ideas, or general feedback.
From ABP Sensei
Registers services in ABP Framework using ITransientDependency/IScopedDependency/ISingletonDependency, [Dependency], [ExposeServices], and Autofac integration. Use for automatic or manual DI registration.
npx claudepluginhub burakdmir/abp-skills --plugin abp-senseiHow this skill is triggered — by the user, by Claude, or both
Slash command
/abp-sensei:abp-dependency-injectionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
User asks about dependency injection, DI, ITransientDependency, ISingletonDependency, IScopedDependency, [Dependency] attribute, [ExposeServices] attribute, auto service registration, or Autofac in ABP Framework.
Applies C++ Core Guidelines to write, review, or refactor C++ code. Enforces modern, safe, and idiomatic practices for C++17/20/23.
Share bugs, ideas, or general feedback.
User asks about dependency injection, DI, ITransientDependency, ISingletonDependency, IScopedDependency, [Dependency] attribute, [ExposeServices] attribute, auto service registration, or Autofac in ABP Framework.
ABP's DI system is built on Microsoft's Microsoft.Extensions.DependencyInjection with:
ITransientDependency, ISingletonDependency, IScopedDependency[Dependency] for fine-grained control[ExposeServices] to control exposed interfacesABP 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) { ... }
}
public class BlogModule : AbpModule
{
public BlogModule()
{
SkipAutoServiceRegistration = true;
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Manual registration
context.Services.AddAssemblyOf<BlogModule>();
}
}
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 { }
More control over registration:
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class TaxCalculator
{
}
| 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.
Control which interfaces a class exposes:
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ICalculator, ITaxCalculator, ICanCalculate, ITransientDependency
{
}
ITaxCalculator can be injectedTaxCalculator, ICalculator, ICanCalculate are NOT injectable[ExposeServices(typeof(ITaxCalculator), typeof(ICalculator))]
public class TaxCalculator : ICalculator, ITaxCalculator, ITransientDependency
{
}
Without [ExposeServices], all implemented interfaces are exposed:
public class TaxCalculator : ICalculator, ITaxCalculator, ITransientDependency
{
}
// Can inject: TaxCalculator, ICalculator, ITaxCalculator
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ITaxCalculator, ITransientDependency
{
}
ReplaceServices = true → replaces existing ITaxCalculator registrationExposeServices → only ITaxCalculator can be injectedITransientDependency → transient lifetime (overridden by [Dependency] if specified)These types are automatically registered by ABP:
AbpModule implementationsABP requires a DI provider that supports dynamic proxying for:
Startup templates come with Autofac pre-installed.
dotnet add package Volo.Abp.Autofac
[DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule { }
In Program.cs:
builder.Host.UseAutofac();
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.
public class MyService : ITransientDependency
{
private readonly IEmailSender _emailSender;
public MyService(IEmailSender emailSender)
{
_emailSender = emailSender;
}
}
public class MyService : ITransientDependency
{
public IEmailSender EmailSender { get; set; }
}
public class MyService : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoWork()
{
var emailSender = _serviceProvider.GetRequiredService<IEmailSender>();
}
}
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>();
}
ITransientDependency (default)[Dependency(ReplaceServices = true)] to override framework services[ExposeServices] to limit exposed interfacesIScopedDependency for per-request state (HTTP context, etc.)ISingletonDependency only for stateless services or cachesIServiceProvider resolutionpublic class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookAppService(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
}
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);
}
}
[Dependency(ReplaceServices = true)]
public class MyCustomEmailSender : IEmailSender, ITransientDependency
{
public async Task SendAsync(string to, string subject, string body)
{
// Custom email logic
}
}