Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Simple Injector
https://github.com/simpleinjector/simpleinjector
Admin
Simple Injector is a lightweight dependency injection library for .NET applications that promotes
...
Tokens:
8,274
Snippets:
69
Trust Score:
6.5
Update:
1 week ago
Context
Skills
Chat
Benchmark
82
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Simple Injector Simple Injector is a fast, lightweight dependency injection (DI) library for .NET that promotes best practices and enables highly maintainable applications. Designed with simplicity and performance in mind, it provides a carefully selected set of features including constructor injection, decorator registration, lifestyle management, and comprehensive container verification to help developers build loosely coupled, testable code following SOLID principles. The library supports multiple .NET platforms including .NET 4.5+, .NET Standard, .NET Core, .NET 5+, Xamarin, and Universal Windows Programs. Simple Injector differentiates itself from other DI containers through features like automatic verification of the container's configuration, diagnostic services for detecting common configuration mistakes, and first-class support for the decorator pattern. It is optimized to run in partial/medium trust environments and delivers blazing fast performance. ## Core Container API ### Container Creation and Basic Registration The `Container` class is the central component of Simple Injector. It holds all registrations and is responsible for resolving instances. ```csharp using SimpleInjector; // Create a new container var container = new Container(); // Register a concrete type (transient by default) container.Register<UserService>(); // Register an interface to implementation mapping container.Register<IUserRepository, SqlUserRepository>(); // Register with explicit lifestyle container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Transient); container.Register<ILogger, FileLogger>(Lifestyle.Singleton); // Register using a delegate factory container.Register<ITimeProvider>(() => new SystemTimeProvider(), Lifestyle.Singleton); // Verify the container configuration (recommended) container.Verify(); // Resolve instances var userService = container.GetInstance<UserService>(); var repository = container.GetInstance<IUserRepository>(); ``` ### Singleton Registration Register types as singletons for shared instances across the application lifetime. Singleton instances are thread-safe and disposed when the container is disposed. ```csharp var container = new Container(); // Register a singleton using the type container.RegisterSingleton<ILogger, ConsoleLogger>(); // Register a singleton with a factory delegate container.RegisterSingleton<IConfiguration>(() => new AppConfiguration()); // Register an existing instance (instance won't be disposed by container) var existingLogger = new FileLogger("app.log"); container.RegisterInstance<ILogger>(existingLogger); // Verify and use container.Verify(); var logger1 = container.GetInstance<ILogger>(); var logger2 = container.GetInstance<ILogger>(); // logger1 and logger2 are the same instance ``` ### Resolving Instances Simple Injector provides multiple ways to retrieve registered instances from the container. ```csharp var container = new Container(); container.Register<IOrderService, OrderService>(); container.Register<ILogger, ConsoleLogger>(Lifestyle.Singleton); container.Verify(); // Get a single instance by generic type var orderService = container.GetInstance<IOrderService>(); // Get a single instance by Type object var logger = container.GetInstance(typeof(ILogger)); // Get the registration information (InstanceProducer) InstanceProducer? producer = container.GetRegistration<IOrderService>(); if (producer != null) { var service = producer.GetInstance(); } // Get registration with throw option InstanceProducer producer2 = container.GetRegistration(typeof(IOrderService), throwOnFailure: true); // IServiceProvider implementation (returns null if not registered) IServiceProvider serviceProvider = container; object? service = serviceProvider.GetService(typeof(IOrderService)); ``` ## Lifestyle Management ### Built-in Lifestyles Simple Injector provides three core lifestyles for controlling instance caching behavior. ```csharp var container = new Container(); // Transient: New instance every time (default) container.Register<ITransientService, TransientService>(Lifestyle.Transient); // Singleton: Single instance for the container's lifetime container.Register<ISingletonService, SingletonService>(Lifestyle.Singleton); // Scoped: Instance per scope (requires DefaultScopedLifestyle configuration) container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle(); container.Register<IScopedService, ScopedService>(Lifestyle.Scoped); container.Verify(); // Using scoped lifestyle using (AsyncScopedLifestyle.BeginScope(container)) { var scoped1 = container.GetInstance<IScopedService>(); var scoped2 = container.GetInstance<IScopedService>(); // scoped1 and scoped2 are the same instance within this scope } ``` ### Hybrid Lifestyles Create custom lifestyles that combine multiple lifestyles based on runtime conditions. ```csharp var container = new Container(); // Create a hybrid that uses ThreadScopedLifestyle when available, falls back to Transient var hybridLifestyle = Lifestyle.CreateHybrid( defaultLifestyle: new ThreadScopedLifestyle(), fallbackLifestyle: Lifestyle.Transient); container.Register<IUserRepository, SqlUserRepository>(hybridLifestyle); // Hybrid with custom predicate var conditionalHybrid = Lifestyle.CreateHybrid( lifestyleSelector: () => HttpContext.Current != null, trueLifestyle: new WebRequestLifestyle(), falseLifestyle: new ThreadScopedLifestyle()); container.Register<IDbContext, AppDbContext>(conditionalHybrid); container.Verify(); ``` ### Custom Lifestyles Create entirely custom lifestyles for specialized caching scenarios. ```csharp // Create a lifestyle that caches instances for 10 minutes var timedLifestyle = Lifestyle.CreateCustom( name: "Timed (10 minutes)", lifestyleApplierFactory: instanceCreator => { var syncRoot = new object(); var expirationTime = DateTime.MinValue; object? cachedInstance = null; return () => { lock (syncRoot) { if (DateTime.UtcNow > expirationTime) { cachedInstance = instanceCreator(); expirationTime = DateTime.UtcNow.AddMinutes(10); } return cachedInstance!; } }; }); var container = new Container(); container.Register<IExpensiveService, ExpensiveService>(timedLifestyle); container.Verify(); ``` ## Decorator Registration ### Basic Decorator Pattern Simple Injector has first-class support for the decorator pattern, automatically wrapping registered services. ```csharp public interface ICommandHandler<TCommand> { void Handle(TCommand command); } public class CreateOrderHandler : ICommandHandler<CreateOrderCommand> { public void Handle(CreateOrderCommand command) { /* implementation */ } } public class LoggingDecorator<TCommand> : ICommandHandler<TCommand> { private readonly ICommandHandler<TCommand> _decorated; private readonly ILogger _logger; public LoggingDecorator(ICommandHandler<TCommand> decorated, ILogger logger) { _decorated = decorated; _logger = logger; } public void Handle(TCommand command) { _logger.Log($"Handling {typeof(TCommand).Name}"); _decorated.Handle(command); _logger.Log($"Handled {typeof(TCommand).Name}"); } } var container = new Container(); container.Register<ILogger, ConsoleLogger>(Lifestyle.Singleton); container.Register<ICommandHandler<CreateOrderCommand>, CreateOrderHandler>(); // Register the decorator - it will wrap all ICommandHandler<T> registrations container.RegisterDecorator(typeof(ICommandHandler<>), typeof(LoggingDecorator<>)); container.Verify(); // Returns LoggingDecorator<CreateOrderCommand> wrapping CreateOrderHandler var handler = container.GetInstance<ICommandHandler<CreateOrderCommand>>(); ``` ### Conditional Decorators Apply decorators conditionally based on the decorated type or other contextual information. ```csharp public class ValidationDecorator<TCommand> : ICommandHandler<TCommand> { private readonly ICommandHandler<TCommand> _decorated; public ValidationDecorator(ICommandHandler<TCommand> decorated) { _decorated = decorated; } public void Handle(TCommand command) { // Validate command... _decorated.Handle(command); } } var container = new Container(); container.Register<ICommandHandler<CreateOrderCommand>, CreateOrderHandler>(); container.Register<ICommandHandler<DeleteOrderCommand>, DeleteOrderHandler>(); // Apply ValidationDecorator only when the command has validation attributes container.RegisterDecorator( typeof(ICommandHandler<>), typeof(ValidationDecorator<>), lifestyle: Lifestyle.Transient, predicate: context => { var commandType = context.ServiceType.GetGenericArguments()[0]; return commandType.GetProperties() .Any(p => p.GetCustomAttributes(typeof(ValidationAttribute), true).Any()); }); container.Verify(); ``` ### Multiple Decorators Stack multiple decorators in a specific order - decorators are applied in registration order. ```csharp var container = new Container(); container.Register<ICommandHandler<CreateOrderCommand>, CreateOrderHandler>(); // Decorators are applied in order of registration // The last registered decorator is the outermost container.RegisterDecorator(typeof(ICommandHandler<>), typeof(ValidationDecorator<>)); container.RegisterDecorator(typeof(ICommandHandler<>), typeof(LoggingDecorator<>)); container.RegisterDecorator(typeof(ICommandHandler<>), typeof(TransactionDecorator<>)); container.Verify(); // Resolves: TransactionDecorator -> LoggingDecorator -> ValidationDecorator -> CreateOrderHandler var handler = container.GetInstance<ICommandHandler<CreateOrderCommand>>(); ``` ## Collection Registration ### Registering Collections Register multiple implementations of a service as a collection. ```csharp public interface IEventHandler<TEvent> { void Handle(TEvent e); } public class OrderCreatedEmailHandler : IEventHandler<OrderCreated> { } public class OrderCreatedInventoryHandler : IEventHandler<OrderCreated> { } public class OrderCreatedAuditHandler : IEventHandler<OrderCreated> { } var container = new Container(); // Register a collection of types container.Collection.Register<IEventHandler<OrderCreated>>( typeof(OrderCreatedEmailHandler), typeof(OrderCreatedInventoryHandler), typeof(OrderCreatedAuditHandler)); // Or auto-register from assemblies container.Collection.Register<IEventHandler<OrderCreated>>(typeof(Program).Assembly); container.Verify(); // Resolve all handlers IEnumerable<IEventHandler<OrderCreated>> handlers = container.GetAllInstances<IEventHandler<OrderCreated>>(); foreach (var handler in handlers) { handler.Handle(new OrderCreated()); } ``` ### Appending to Collections Add implementations to collections dynamically. ```csharp var container = new Container(); // Initial registration container.Collection.Register<IPlugin>(typeof(CorePlugin), typeof(SecurityPlugin)); // Append additional types later container.Collection.Append<IPlugin, LoggingPlugin>(); container.Collection.Append<IPlugin, CachingPlugin>(Lifestyle.Singleton); // Append with a factory container.Collection.Append<IPlugin>(() => new DynamicPlugin(), Lifestyle.Transient); // Append an existing instance var customPlugin = new CustomPlugin(); container.Collection.AppendInstance<IPlugin>(customPlugin); container.Verify(); var plugins = container.GetAllInstances<IPlugin>().ToList(); // Contains: CorePlugin, SecurityPlugin, LoggingPlugin, CachingPlugin, DynamicPlugin, CustomPlugin ``` ### Creating Standalone Collections Create collections that can be used independently without registering them in the container. ```csharp var container = new Container(); container.Register<IValidator<Order>, OrderValidator>(); container.Register<IValidator<Customer>, CustomerValidator>(); // Create a standalone collection (not registered in container) IList<IValidator<Order>> validators = container.Collection.Create<IValidator<Order>>( typeof(RequiredFieldsValidator<Order>), typeof(BusinessRulesValidator<Order>)); container.Verify(); // The collection is lazy - instances are resolved on enumeration foreach (var validator in validators) { validator.Validate(order); } ``` ## Conditional Registration ### Basic Conditional Registration Register implementations conditionally based on the consumer. ```csharp public interface ILogger { void Log(string message); } public class ConsoleLogger : ILogger { } public class FileLogger : ILogger { } public class NullLogger : ILogger { } var container = new Container(); // Register FileLogger for OrderService, ConsoleLogger for everything else container.RegisterConditional<ILogger, FileLogger>( Lifestyle.Singleton, context => context.Consumer.ImplementationType == typeof(OrderService)); container.RegisterConditional<ILogger, ConsoleLogger>( Lifestyle.Singleton, context => context.Consumer.ImplementationType != typeof(OrderService)); // Fallback registration (when no other conditional matches) container.RegisterConditional<ILogger, NullLogger>( context => !context.Handled); container.Verify(); ``` ### Conditional with Open Generics Apply conditional registration to open generic types. ```csharp public interface IRepository<T> { } public class SqlRepository<T> : IRepository<T> { } public class CachedRepository<T> : IRepository<T> { } var container = new Container(); // Use CachedRepository for read-heavy entities container.RegisterConditional( typeof(IRepository<>), typeof(CachedRepository<>), Lifestyle.Scoped, context => typeof(IReadHeavyEntity).IsAssignableFrom( context.ServiceType.GetGenericArguments()[0])); // Use SqlRepository for everything else container.RegisterConditional( typeof(IRepository<>), typeof(SqlRepository<>), Lifestyle.Scoped, context => !context.Handled); container.Verify(); ``` ## Container Verification and Diagnostics ### Verifying Container Configuration The `Verify` method validates the entire container configuration and catches common mistakes. ```csharp var container = new Container(); container.Register<IOrderService, OrderService>(); container.Register<IOrderRepository, SqlOrderRepository>(); container.Register<ILogger, ConsoleLogger>(Lifestyle.Singleton); // Verify builds all registrations and runs diagnostic checks // Throws InvalidOperationException on configuration errors // Throws DiagnosticVerificationException on diagnostic warnings (when using VerifyAndDiagnose) try { container.Verify(VerificationOption.VerifyAndDiagnose); Console.WriteLine("Container configuration is valid!"); } catch (InvalidOperationException ex) { Console.WriteLine($"Configuration error: {ex.Message}"); } catch (DiagnosticVerificationException ex) { foreach (var result in ex.Errors) { Console.WriteLine($"Warning: {result.Description}"); } } ``` ### Diagnostic Analysis Analyze the container for potential issues like lifestyle mismatches. ```csharp using SimpleInjector.Diagnostics; var container = new Container(); container.Register<IOrderService, OrderService>(Lifestyle.Transient); container.Register<IOrderRepository, SqlOrderRepository>(Lifestyle.Singleton); // Don't use VerifyAndDiagnose to get individual results container.Verify(VerificationOption.VerifyOnly); // Analyze for diagnostic warnings var results = Analyzer.Analyze(container); foreach (var result in results) { Console.WriteLine($"[{result.Severity}] {result.DiagnosticType}: {result.Description}"); // Example output: // [Warning] LifestyleMismatch: OrderService (Transient) depends on // IOrderRepository (Singleton). This might cause lifestyle mismatch issues. } ``` ## Instance Initializers ### Type-Based Initializers Run initialization logic after instances are created. ```csharp public interface IInitializable { void Initialize(); } var container = new Container(); container.Register<IOrderService, OrderService>(); container.Register<ILogger, ConsoleLogger>(Lifestyle.Singleton); // Register initializer for all IInitializable implementations container.RegisterInitializer<IInitializable>(instance => { instance.Initialize(); }); // Register initializer for all objects (useful for debugging) container.RegisterInitializer<object>(instance => { Debug.WriteLine($"Created: {instance.GetType().Name}"); }); container.Verify(); ``` ### Conditional Initializers Apply initializers based on contextual information. ```csharp var container = new Container(); container.Register<IOrderService, OrderService>(); // Apply initializer only to specific types container.RegisterInitializer( instanceData => { var service = instanceData.Instance as IRequiresContext; service?.SetContext(new RequestContext()); }, context => typeof(IRequiresContext).IsAssignableFrom( context.Registration.ImplementationType)); container.Verify(); ``` ## Advanced Registration Features ### Open Generic Registration Register open generic types that are resolved based on the requested closed generic type. ```csharp public interface IValidator<T> { ValidationResult Validate(T instance); } public class Validator<T> : IValidator<T> { } public interface IRepository<T> where T : class { } public class Repository<T> : IRepository<T> where T : class { } var container = new Container(); // Register open generic types container.Register(typeof(IValidator<>), typeof(Validator<>), Lifestyle.Transient); container.Register(typeof(IRepository<>), typeof(Repository<>), Lifestyle.Scoped); container.Verify(); // Resolve closed generic types var orderValidator = container.GetInstance<IValidator<Order>>(); var customerRepo = container.GetInstance<IRepository<Customer>>(); ``` ### Registration Events Hook into the registration pipeline with expression building events. ```csharp var container = new Container(); // Intercept expression building for property injection container.ExpressionBuilding += (sender, e) => { if (e.KnownImplementationType != null) { var properties = e.KnownImplementationType .GetProperties() .Where(p => p.GetCustomAttribute<InjectAttribute>() != null); foreach (var property in properties) { var producer = container.GetRegistration(property.PropertyType, true); e.KnownRelationships.Add( new KnownRelationship(property.PropertyType, e.Lifestyle, producer)); } } }; // Intercept after expression is built container.ExpressionBuilt += (sender, e) => { Console.WriteLine($"Built expression for {e.RegisteredServiceType.Name}"); }; // Handle unregistered types container.ResolveUnregisteredType += (sender, e) => { if (e.UnregisteredServiceType.IsInterface && e.UnregisteredServiceType.Name.StartsWith("INullable")) { e.Register(() => null); } }; container.Verify(); ``` ### Using Registration Objects Create and reuse `Registration` objects for advanced scenarios. ```csharp var container = new Container(); // Create a registration that can be reused across multiple service types Registration fooBarRegistration = Lifestyle.Singleton.CreateRegistration<FooBar>(container); // Register the same singleton for multiple interfaces container.AddRegistration<IFoo>(fooBarRegistration); container.AddRegistration<IBar>(fooBarRegistration); container.Verify(); // Both resolve to the same singleton instance var foo = container.GetInstance<IFoo>(); var bar = container.GetInstance<IBar>(); // foo and bar reference the same FooBar instance ``` ## Integration Patterns Simple Injector is designed to integrate seamlessly with popular application frameworks including ASP.NET Core, ASP.NET MVC, Web API, WCF, and many others. The core pattern involves creating a container at application startup, configuring all registrations, verifying the configuration, and then integrating with the framework's dependency resolution mechanism. For web applications, scoped lifestyles are typically used for per-request dependencies like database contexts and unit-of-work patterns. Integration packages provide framework-specific scoped lifestyles (like `WebRequestLifestyle` for ASP.NET or `AsyncScopedLifestyle` for ASP.NET Core) and wire up the container as the application's dependency resolver. The verification step should always be called during application startup to catch configuration errors early, before the application starts handling requests.