-
Notifications
You must be signed in to change notification settings - Fork 0
Registration
Jim Burlison edited this page Dec 5, 2025
·
1 revision
This guide covers all the ways to register services with SSDI.
The simplest registration maps a type to itself:
container.Configure(c =>
{
c.Export<MyService>();
});
var service = container.Locate<MyService>();Use the non-generic overload for runtime type registration:
Type serviceType = typeof(MyService);
container.Configure(c =>
{
c.Export(serviceType);
});
object service = container.Locate(serviceType);Map an implementation to its interface:
container.Configure(c =>
{
c.Export<SqlRepository>().As<IRepository>();
});
var repo = container.Locate<IRepository>(); // Returns SqlRepositoryA single type can be registered as multiple interfaces:
container.Configure(c =>
{
c.Export<UniversalService>()
.As<IReader>()
.As<IWriter>()
.As<IProcessor>();
});
var reader = container.Locate<IReader>();
var writer = container.Locate<IWriter>();
// Both return the same type, but instances depend on lifetimeRegister multiple implementations of the same interface:
container.Configure(c =>
{
c.Export<AuthHandler>().As<IPacketHandler>();
c.Export<GameHandler>().As<IPacketHandler>();
c.Export<ChatHandler>().As<IPacketHandler>();
});
// Resolve single (returns first registered)
var handler = container.Locate<IPacketHandler>(); // Returns AuthHandler
// Resolve all implementations
var allHandlers = container.Locate<IEnumerable<IPacketHandler>>();
// Returns: [AuthHandler, GameHandler, ChatHandler]Register pre-built instances as singletons:
var config = new Configuration
{
ServerName = "GameServer",
Port = 8080
};
container.Configure(c =>
{
c.ExportInstance(config).As<IConfiguration>();
});
var resolvedConfig = container.Locate<IConfiguration>();
// Returns the exact instance you registered- Configuration objects loaded from files
- External dependencies created outside the container
- Mock objects for testing
- Shared resources initialized before container setup
// Real-world example
var logger = new FileLogger("game.log");
var settings = JsonSerializer.Deserialize<GameSettings>(File.ReadAllText("settings.json"));
container.Configure(c =>
{
c.ExportInstance(logger).As<ILogger>();
c.ExportInstance(settings).As<GameSettings>();
});Register types discovered at runtime:
// Register all types implementing an interface from an assembly
var assembly = Assembly.GetExecutingAssembly();
container.Configure(c =>
{
foreach (var type in assembly.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract))
{
c.Export(type).As<IPlugin>();
}
});
var plugins = container.Locate<IEnumerable<IPlugin>>();public void LoadPlugins(string pluginDirectory)
{
foreach (var dll in Directory.GetFiles(pluginDirectory, "*.dll"))
{
var assembly = Assembly.LoadFrom(dll);
container.Configure(c =>
{
foreach (var type in assembly.GetTypes()
.Where(t => typeof(IGamePlugin).IsAssignableFrom(t)))
{
c.Export(type).As<IGamePlugin>();
}
});
}
}You can call Configure multiple times. This is useful for:
- Modular registration
- Plugin loading
- Conditional registration
// Core services
container.Configure(c =>
{
c.Export<GameEngine>().Lifestyle.Singleton();
c.Export<InputManager>().Lifestyle.Singleton();
});
// Feature-specific services
container.Configure(c =>
{
c.Export<InventorySystem>();
c.Export<CraftingSystem>();
});
// Optional services based on configuration
if (enableMultiplayer)
{
container.Configure(c =>
{
c.Export<NetworkManager>().Lifestyle.Singleton();
c.Export<PlayerSync>();
});
}Combine registration with Lifetimes:
container.Configure(c =>
{
// Transient (default) - new instance each time
c.Export<Projectile>();
// Singleton - single shared instance
c.Export<GameEngine>().Lifestyle.Singleton();
// Scoped - one per scope
c.Export<PlayerInventory>().Lifestyle.Scoped();
// Interface with lifetime
c.Export<SqlRepository>()
.As<IRepository>()
.Lifestyle.Singleton();
});Provide constructor parameters at registration time:
container.Configure(c =>
{
// By type
c.Export<GameServer>()
.WithCtorParam<int>(8080)
.WithCtorParam<string>("MyServer");
// By name
c.Export<DatabaseConnection>()
.WithCtorParam("connectionString", "Server=localhost;Database=game");
// By position
c.Export<NetworkClient>()
.WithCtorParam(0, "192.168.1.1")
.WithCtorParam(1, 9999);
// Multiple positional
c.Export<ComplexService>()
.WithCtorPositionalParams("param1", 42, true, 3.14);
});See Parameter Injection for more details.
Check if a type is registered before resolving:
if (container.IsRegistered<ILogger>())
{
var logger = container.Locate<ILogger>();
logger.Log("Service found!");
}
// Non-generic version
bool isRegistered = container.IsRegistered(typeof(ILogger));container.Configure(c =>
{
c.Export<DefaultLogger>().As<ILogger>();
});
// Later, conditionally add specialized logger
if (!container.IsRegistered<IFileLogger>())
{
container.Configure(c =>
{
c.Export<FileLogger>().As<IFileLogger>();
});
}// ✅ Good - decoupled
c.Export<SqlRepository>().As<IRepository>();
// ⚠️ Okay for internal services
c.Export<GameEngine>();
// ❌ Avoid - tight coupling
var repo = container.Locate<SqlRepository>();// Singleton for shared state
c.Export<GameState>().Lifestyle.Singleton();
// Transient for stateless services
c.Export<DamageCalculator>();
// Scoped for per-request/per-player
c.Export<PlayerSession>().Lifestyle.Scoped();// Core module
void RegisterCoreServices(DependencyInjectionContainer container)
{
container.Configure(c =>
{
c.Export<GameEngine>().Lifestyle.Singleton();
c.Export<InputManager>().Lifestyle.Singleton();
c.Export<AudioManager>().Lifestyle.Singleton();
});
}
// Combat module
void RegisterCombatServices(DependencyInjectionContainer container)
{
container.Configure(c =>
{
c.Export<CombatSystem>();
c.Export<DamageCalculator>();
c.Export<SkillManager>().As<ISkillManager>();
});
}container.Configure(c =>
{
// Dependencies first
c.Export<Logger>().As<ILogger>();
c.Export<Database>().As<IDatabase>();
// Then services that depend on them
c.Export<UserRepository>().As<IUserRepository>();
c.Export<UserService>().As<IUserService>();
});- Lifetimes - Configure service lifetimes
- Parameter Injection - Inject constructor parameters
- Unregistration & Events - Remove and replace registrations