Overview of StrongInject.Samples.ConsoleApp
mainall_messages and forwarding them to specific recipient inboxes using a topic naming convention of inbox_[user-id].repository·main·Indexed 21 days ago
https://github.com/yairhalberstadt/stronginjectA compile-time dependency injection library for .NET using Roslyn Source Generators. It provides compile-time safety, high performance without reflection, and full support for asynchronous initialization and disposal. The library includes integration patterns for ASP.NET Core, Xamarin.Forms, WPF, and console applications, featuring support for scoped execution via Run/RunAsync and manual lifetime control through Owned<T> wrappers.
all_messages and forwarding them to specific recipient inboxes using a topic naming convention of inbox_[user-id].A container acts as a factory that provides instances of a type on demand and manages their disposal.
To create a container, you must inherit from either:
IContainer<T>: For synchronous resolution.IAsyncContainer<T>: Required if resolution must be asynchronous.Important: You must ensure the container is capable of resolving T by providing suitable [Register] attributes. If no registration is found, you will encounter a compile-time error.
using StrongInject;
[Register(typeof(A))]
public partial class MyContainer : IContainer<A> { }
public class A : IDisposable { public void Dispose() { } }
var myContainer = new MyContainer();You can register a method as a provider for a type by applying the [Factory] attribute to it. StrongInject will resolve all parameters of the method and call it to create the instance.
Key Behaviors:
Task<T> or ValueTask<T>, it is registered as a provider for T and must be resolved asynchronously.Scope parameter in the [Factory] attribute determines the lifetime of the instance created by the method.[Factory(Scope.SingleInstance)]
private MyService CreateMyService(IDependency dep) => new MyService(dep);While [RegisterModule] imports public static members, you can also import protected and protected internal members by having your container class inherit from the module class.
This is functionally similar to importing the module, but it grants access to the protected members defined in the module's hierarchy.
The ASP.NET Core sample highlights several advanced patterns for using StrongInject:
InstancePerDependency, while caches should be SingleInstance.IServiceProvider as a parameter to the StrongInject Container. This allows StrongInject to resolve types registered in the standard Microsoft DI container, such as ILogger<T>.ILogger<T> for all T simultaneously.Microsoft.Extensions.DependencyInjection does not. If a dependency (like a DatabaseUsersCache) requires asynchronous preparation, you should design the consuming service to handle asynchronous requests rather than attempting to resolve the dependency asynchronously through the standard DI container.A Decorator does not provide a new instance of a type; instead, it wraps or modifies an existing underlying instance that is resolved through normal registration.
If multiple decorators are registered for the same type, they are applied in an "onion style" (wrapping one inside another). While the application order is deterministic, it is an implementation detail and should not be relied upon for logic.
Limitations:
[Instance] fields or properties when Options.DoNotDecorate is applied.The Options enum is a [Flags] enum used to modify how types are registered in the container. You can combine multiple options using the bitwise OR (|) operator.
To simplify syntax, you can use using static StrongInject.Options; to reference members directly without the Options. prefix.
using static StrongInject.Options;
// Example of combining options
var options = UseAsFactory | DoNotDecorate;When StrongInject needs to resolve a type, it checks potential providers in a specific sequence and stops as soon as it finds a provider capable of supplying the instance. The order is:
Task<T> or ValueTask<T>, it creates an async delegate.The [Instance] attribute accepts an Options parameter to customize how the instance is registered.
Key capabilities include:
IFactory<T> or IAsyncFactory<T>, it can be registered as T, along with T's base classes, interfaces, and factories.Options.DoNotDecorate.Note on Disposal: StrongInject will not dispose of instance fields or properties. This design choice allows modules containing these instances to be safely shared among multiple containers.
// Example of opting out of decoration
[Instance(Options.DoNotDecorate)] public static readonly MyService _service = new MyService();decoratedType.When resolving a single instance of a type T, StrongInject requires that there is exactly one best registration for that type. If multiple registrations exist and none qualify as the 'best', StrongInject will throw an error.
Container and ModuleA both define a registration for SomeInterface, the one on the Container is the best registration.Container imports both ModuleA and ModuleB, and both modules define a registration for SomeInterface, resolving SomeInterface will error because neither is 'better' than the other.Container imports ModuleA, and ModuleA imports ModuleB, then ModuleA's registration is the best registration.Container. This will override all imported registrations.