Overview
Silky uses Autofac as its IoC container, extended with automatic assembly scanning and convention-based registration. The DI system follows the same patterns as ABP Framework, making it intuitive for developers familiar with that ecosystem.
DI Marker Interfaces
Implement one of the following marker interfaces to auto-register a class — no explicit services.AddXxx() call needed:
| Interface | Lifetime | Description |
|---|---|---|
ISingletonDependency | Singleton | One instance for the entire application lifetime |
IScopedDependency | Scoped | One instance per RPC request / HTTP request |
ITransientDependency | Transient | New instance every time it is resolved |
Example
// Auto-registered as Scoped
public class OrderRepository : IOrderRepository, IScopedDependency
{
// ...
}
// Auto-registered as Singleton
public class RpcTokenCache : IRpcTokenCache, ISingletonDependency
{
// ...
}
Silky scans all loaded assemblies for these marker interfaces at startup and registers them in the Autofac container.
Resolving Dependencies
Use constructor injection (the recommended pattern):
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly IOrderRepository _orderRepo;
private readonly IAccountAppService _accountService; // remote RPC proxy injected
public OrderAppService(
IOrderRepository orderRepo,
IAccountAppService accountService)
{
_orderRepo = orderRepo;
_accountService = accountService;
}
}
Property Injection
For optional dependencies or circular dependency situations, use property injection via the [Dependency] attribute:
public class OrderAppService : IOrderAppService, IScopedDependency
{
[Dependency(Required = false)]
public ILogger<OrderAppService> Logger { get; set; }
}
Manual Registration in Modules
For types that don't implement the marker interfaces, register manually in your module's ConfigureServices:
public class OrderDomainModule : SilkyModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IOrderNumberGenerator, SequentialOrderNumberGenerator>();
// Autofac-specific registration (access builder via context)
context.Services.AddOptions<OrderSettings>()
.Bind(context.Services.GetConfiguration().GetSection("Order"));
}
}
Accessing the Container
In rare cases where you need to resolve services outside constructor injection:
public class SomeService : IScopedDependency
{
private readonly IServiceProvider _serviceProvider;
public SomeService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task DoSomethingAsync()
{
using var scope = _serviceProvider.CreateScope();
var repo = scope.ServiceProvider.GetRequiredService<IProductRepository>();
// use repo
}
}
Prefer constructor injection over service locator. The service locator pattern (IServiceProvider.GetService) makes dependencies implicit and harder to test.
RPC Proxy Auto-Registration
Remote service interfaces (annotated with [ServiceRoute]) are automatically registered as Autofac dynamic proxies. When you inject a remote service interface, Silky provides a proxy that transparently routes the call to the remote service over TCP RPC.
// No registration needed — Silky registers this proxy automatically
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly IAccountAppService _accountService; // remote proxy!
public OrderAppService(IAccountAppService accountService)
{
_accountService = accountService;
}
}
