Immediate.Injections is a support package for Microsoft.Extensions.DependencyInjection which allows declaring
registrations through attributes. This package supports multiple registration strategies, duplicate-handling strategies,
tagging, and much more.
dotnet add package Immediate.Injections
Apply one of the three lifetime attributes to a class or record:
[RegisterSingleton]publicclassMyService;[RegisterScoped]publicclassMyScopedService;[RegisterTransient]publicclassMyTransientService<T>;By default (when no RegistrationStrategy is set at the attribute or assembly level), a class is registered as itself.
Generic classes will be registered using open-generics.
In your Program.cs, add a call to services.AddXxxServices(), where Xxx is the application identifier. By default,
this is the short form of the assembly name. For example:
- For a project named
Web, it will beservices.AddWebServices() - For a project named
Application.Web, it will beservices.AddApplicationWebServices()
However, this name can be overridden using [assembly: ImmediateAssemblyIdentifierAttribute("SomeIdentifier")].
Tags can be passed to selectively register only tagged services:
[RegisterSingleton(Tags=["tag-a"])]publicclassMyService;builder.Services.AddMyProjectServices("tag-a","tag-b");All three lifetime attributes — RegisterSingleton, RegisterScoped, RegisterTransient — share the same properties.
Registers the class as the specified service type. The class must be assignable to it.
[RegisterSingleton(ServiceType=typeof(IMyService))]publicclassMyService:IMyService{}Alternatively, a concrete registration may be declared using generic attributes.
[RegisterSingleton<IMyService>]publicclassMyService:IMyService{}[RegisterScoped<IService<string>>]publicclassMyService<T>:IMyService<string>Controls which service types are generated. Mutually exclusive with ServiceType.
| Value | Effect |
|---|---|
None (default) | Registers as ServiceType if provided, otherwise as the class itself |
Self | Registers as the concrete class |
ImplementedInterfaces | Registers as each interface the class implements |
SelfAndImplementedInterfaces | Registers as the concrete class and each interface |
[RegisterSingleton(RegistrationStrategy=RegistrationStrategy.ImplementedInterfaces)]publicclassMyService:IMyService{}Controls what happens when a registration for the same service type already exists.
| Value | Generated call |
|---|---|
Append (default) | services.Add(...) |
Skip | services.TryAdd(...) |
Replace | services.Replace(...) |
Registers the service as a keyed service.
[RegisterSingleton(ServiceKey="my-key")]publicclassMyService{}Name of a static factory method on the class to use as ImplementationFactory. The method must be static, return the
class type, and accept (IServiceProvider) for non-keyed or (IServiceProvider, object) for keyed registrations.
Cannot be combined with UseProxyFactory or used on open generic types. Factories cannot be used with generic target
classes.
[RegisterSingleton(Factory=nameof(Create))]publicclassMyService{publicstaticMyServiceCreate(IServiceProvidersp)=>newMyService();}When true, the registration uses ServiceProviderServiceExtensions.GetRequiredService<T> (or the keyed equivalent) as
the factory. This produces a proxy registration — it does not register the implementation itself, but resolves it from
the container.
UseProxyFactory = true be combined with the following:
- A provided
Factory, RegistrationStrategy = Self, or- Generic target classes
[RegisterSingleton(ServiceType=typeof(IMyService),UseProxyFactory=true)]publicclassMyService:IMyService{}Assigns string tags to the registration. When AddXxxServices is called with tag arguments, only registrations that share at least one tag (or registrations with no tags) are included.
[RegisterSingleton(Tags=["worker","background"])]publicclassBackgroundWorker{}ServiceKey and DuplicationStrategy can be configured globally with [RegistrationDefaults] attribute applied to the
assembly.
[assembly:RegistrationDefaults(RegistrationStrategy=RegistrationStrategy.SelfAndImplementedInterfaces,DuplicateStrategy=DuplicateStrategy.Replace,UseProxyFactory=true)]Per-attribute values take precedence over assembly defaults.
Apply this attribute to a static void method to have it called as part of AddXxxServices. The method must accept
IServiceCollection as its first parameter, and optionally ReadOnlySpan<string> as its second parameter to receive
the tags passed to AddXxxServices.
publicstaticclassManualRegistrations{[RegisterServices]publicstaticvoidRegister(IServiceCollectionservices){ ...}// or, to receive tags:[RegisterServices]publicstaticvoidRegisterWithTags(IServiceCollectionservices,ReadOnlySpan<string>tags){ ...}}Note
Immediate.Injections uses a different default registration strategy than Injectio. For a clean migration, set
[assembly: RegistrationDefaults(RegistrationStrategy = RegistrationStrategy.SelfAndImplementedInterfaces, UseProxyFactory = true)]
- The
Tagsparameter receives astring[]instead of a comma-separatedstring. Example:Tags = "foo,bar"becomesTags = ["foo", "bar"] - The
RegistrationStrategy.SelfWithInterfacesenum value changes toRegistrationStrategy.SelfAndImplementedInterfaces - The
Registrationparameter changes toRegistrationStrategy - The
Duplicateparameter becomesDuplicateStrategy - Assembly name override moves from MSBuild property to
[ImmediateAssemblyIdentifier]attribute
Note
Immediate.Injections uses a different default registration strategy than Injectio. For a clean migration, set
[assembly: RegistrationDefaults(RegistrationStrategy = RegistrationStrategy.ImplementedInterfaces)].
- The
[TryRegisterXxx]attributes are removed; but the behavior is implemented using a parameter. Example:DuplicateStrategy = DuplicateStrategy.Skip