VDT.Core.DependencyInjection
6.0.0
dotnet add package VDT.Core.DependencyInjection --version 6.0.0
NuGet\Install-Package VDT.Core.DependencyInjection -Version 6.0.0
<PackageReference Include="VDT.Core.DependencyInjection" Version="6.0.0" />
paket add VDT.Core.DependencyInjection --version 6.0.0
#r "nuget: VDT.Core.DependencyInjection, 6.0.0"
// Install VDT.Core.DependencyInjection as a Cake Addin #addin nuget:?package=VDT.Core.DependencyInjection&version=6.0.0 // Install VDT.Core.DependencyInjection as a Cake Tool #tool nuget:?package=VDT.Core.DependencyInjection&version=6.0.0
VDT.Core.DependencyInjection
Provides extensions for Microsoft.Extensions.DependencyInjection.IServiceCollection
Features
- Flexible service registration
- Convention-based service registration
- Attribute-based service registration
- Decorator pattern implementation
Flexible service registration
The extension method ServiceCollectionExtensions.AddServices
is used to register all services provided by a ServiceRegistrationOptions
object built with
the provided setup action. The ServiceRegistrationOptions
class provides methods to build it in a fluent way:
AddAssembly
adds an assembly to scan for servicesAddAssemblies
adds multiple assemblies to scan for services- Overloads are provided to add multiple assemblies as a parameter array or enumerable
- Overloads are provided to search for assemblies recursively by predicate or assembly name prefix
AddServiceRegistrationProvider
adds a method that returns service types for a given implementation type found in the assemblies- These methods must match the delegate method
ServiceRegistrationProvider
- These methods return a collection of
ServiceRegistration
which contain the service type and optionally the desiredServiceLifetime
- These methods must match the delegate method
UseDefaultServiceLifetime
sets the defaultServiceLifetime
to use if the foundServiceRegistration
does not include aServiceLifetime
UseServiceRegistrar
sets the method to use for registering services- This method must match the delegate method
ServiceRegistrar
- By default a new
ServiceDescriptor
will be created with the found service type, implementation type and lifetime
- This method must match the delegate method
- Please note that the
AddServiceTypeProvider
methods have been deprecated since they are being replaced byAddServiceRegistrationProvider
Example
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddServices(setupAction: options => options
// Add assemblies to scan
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddAssemblies(typeof(MyService).Assembly, typeof(MyOtherService).Assembly)
// Add all project assemblies based on prefix
.AddAssemblies(entryAssembly: typeof(Startup).Assembly, assemblyPrefix: "MyCompany.MySolution")
// Add a service registration provider with a lifetime
.AddServiceRegistrationProvider(
serviceRegistrationProvider: implementationType => implementationType.GetInterfaces()
.Where(serviceType => serviceType.Assembly == implementationType.Assembly)
.Select(new ServiceRegistration(serviceType, ServiceLifetime.Scoped))
)
// Add a service registration provider without a lifetime
.AddServiceRegistrationProvider(
serviceRegistrationProvider: implementationType => implementationType.GetInterfaces()
.Where(serviceType => serviceType.Assembly == implementationType.Assembly)
.Select(new ServiceRegistration(serviceType))
)
// Optional: use a different ServiceLifetime than Scoped by default
.UseDefaultServiceLifetime(serviceLifetime: ServiceLifetime.Transient)
// Optional: provide your own method for registering services
.UseServiceRegistrar(
serviceRegistrar: (services, serviceType, implementationType, serviceLifetime) => services.Add(new ServiceDescriptor(serviceType, implementationType, serviceLifetime))
)
);
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// ...
}
}
Convention-based service registration
The class DefaultServiceRegistrationProviders
contains three ways to register services based on common conventions. Each method creates a
ServiceRegistrationProvider
that can be added to the ServiceRegistrationOptions
to find services to register, and each method takes the ServiceLifetime
of the services found by this provider as an optional parameter.
CreateSingleInterfaceProvider
returns the single interface if an implementation type implements exactly one interfaceCreateInterfaceByNameProvider
returns interface types found on on implementation types that follow the .NET naming guideline of naming class-interface pairs:- Service interface name
IMyService
- Implementation class name
MyService
- Service interface name
CreateGenericInterfaceRegistrationProvider
finds generic types based on a generic type definition:- Service interface name
IRequestHandler<TRequest>
- Implementation class
ExampleRequestHandler : IRequestHandler<ExampleRequest>
- This is useful if you implement generic interface types such request handlers, command handlers or query handlers
- Service interface name
Example
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddServices(setupAction: options => options
// Add assemblies to scan
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddAssembly(assembly: typeof(MyService).Assembly)
// Add default service registration providers
.AddServiceRegistrationProvider(
serviceRegistrationProvider: DefaultServiceRegistrationProviders.CreateSingleInterfaceProvider()
)
.AddServiceRegistrationProvider(
serviceRegistrationProvider: DefaultServiceRegistrationProviders.CreateInterfaceByNameProvider(ServiceLifetime.Scoped)
)
.AddServiceRegistrationProvider(
serviceRegistrationProvider: DefaultServiceRegistrationProviders.CreateGenericInterfaceRegistrationProvider(typeof(IRequestHandler<>))
)
);
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// ...
}
}
Attribute-based service registration
The extension method Attributes.ServiceRegistrationOptionsExtensions.AddAttributeServiceRegistrationProviders
allows you to move registration for your
services from the Startup
class to the services themselves. Simply mark your services or service implementations with the different types of service
attributes to indicate that a service should be registered and use the options extension to add the correct providers.
There are nine attributes available:
Attributes.TransientAttribute
marks a service to be registered as transientAttributes.ScopedAttribute
marks a service to be registered as scopedAttributes.SingletonServiceAttribute
marks a service to be registered as singletonAttributes.TransientServiceAttribute
marks a service to be registered as transient with the supplied implementation typeAttributes.ScopedServiceAttribute
marks a service to be registered as scoped with the supplied implementation typeAttributes.SingletonScopedServiceAttribute
marks a service to be registered as singleton with the supplied implementation typeAttributes.TransientServiceImplementationAttribute
marks a service implementation to be registered as transient for the supplied service typeAttributes.ScopedServiceImplementationAttribute
marks a service implementation to be registered as scoped for the supplied service typeAttributes.SingletonServiceImplementationAttribute
marks a service implementation to be registered as singleton for the supplied service type
The extension methods Attributes.ServiceCollectionExtensions.AddAttributeServices
are convenience methods that you can use if you don't need any other
service registration providers or additional setup of service registration.
Example
// Mark the service to be registered
[ScopedService(implementationType: typeof(Bar))]
public interface IBar {
void Foo();
}
public class Bar : IBar {
public void Foo() {
// ...
}
}
public interface IBar {
void Foo();
}
// Mark the implementation
[ScopedServiceImplementation(serviceType: typeof(IBar))]
public class Bar : IBar {
public void Foo() {
// ...
}
}
public class Startup {
public void ConfigureServices(IServiceCollection services) {
// Register using options
services.AddServices(setupAction: options => options
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddAttributeServiceRegistrationProviders()
);
// Register using convenience method
services.AddAttributeServices(assembly: typeof(Startup).Assembly);
// Register using convenience method and apply decorators
services.AddAttributeServices(assembly: typeof(Startup).Assembly, decoratorSetupAction: options => options.AddAttributeDecorators());
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// ...
}
}
Decorators
The extension methods Decorators.ServiceCollectionExtensions.AddTransient
, Decorators.ServiceCollectionExtensions.AddScoped
and
Decorators.ServiceCollectionExtensions.AddSingleton
with an Action<Decorators.DecoratorOptions>
parameter allow you to register services decorated with
your own implementations of the Decorators.IDecorator
interface.
If you wish to use decorators when using options-based service registration as described above, it is possible to use the
Decorators.ServiceRegistrationOptionsExtensions.UseDecoratorServiceRegistrar
extension method which can apply decorator options to all classes that are
registered using the provided ServiceRegistrationProvider
methods.
The Decorators.IDecorator
interface has three methods:
BeforeExecute
allows you to execute code before execution of the decorated methodAfterExecute
allows you to execute code after execution of the decorated methodOnError
allows you to execute code if the decorated method throws an error
There are two ways to apply decorators to your services: you can apply a custom attribute to the methods on either the service or service imlementation you want decorated, or you can provide predicates with decorator types when registering the services.
Example
public class LogDecorator : IDecorator {
public void BeforeExecute(MethodExecutionContext context) {
Debug.WriteLine($"Executing '{context.TargetType.FullName}.{context.Method.Name}'");
}
public void AfterExecute(MethodExecutionContext context) {
Debug.WriteLine($"Executed '{context.TargetType.FullName}.{context.Method.Name}'");
}
public void OnError(MethodExecutionContext context, System.Exception exception) {
Debug.WriteLine($"Failed to execute '{context.TargetType.FullName}.{context.Method.Name}': {exception.Message}");
}
}
// For attribute based decoration
[AttributeUsage(AttributeTargets.Method)]
public class LogAttribute : Attribute, IDecorateAttribute<LogDecorator> {
}
public interface IExample {
// Decorate from service
[Log]
void Foo();
void Bar();
}
public class Example : IExample {
public void Foo() {
// ...
}
// Decorate from implementation
[Log]
public void Bar() {
// ...
}
}
public class Startup {
public void ConfigureServices(IServiceCollection services) {
// Register services with a provided decorator
services.AddServices(options => options
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddServiceRegistrationProvider(
serviceRegistrationProvider: DefaultServiceRegistrationProviders.CreateInterfaceByNameProvider()
)
.UseDecoratorServiceRegistrar(setupAction: options => options.AddDecorator<LogDecorator>(predicate: method => method.Name == "Foo"))
);
// Register services using attributes
services.AddServices(options => options
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddServiceRegistrationProvider(
serviceRegistrationProvider: DefaultServiceRegistrationProviders.CreateInterfaceByNameProvider()
)
.UseDecoratorServiceRegistrar(setupAction: options => options.AddAttributeDecorators())
);
// Register a single service with a provided decorator
services.AddScoped<IExample, Example>(setupAction: options => options.AddDecorator<LogDecorator>(predicate: method => method.Name == "Foo"));
// Register a single service using attributes
services.AddScoped<IExample, Example>(setupAction: options => options.AddAttributeDecorators());
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// ...
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Castle.Core (>= 5.0.0)
- Microsoft.Extensions.DependencyInjection (>= 6.0.0)
-
net6.0
- Castle.Core (>= 5.0.0)
- Microsoft.Extensions.DependencyInjection (>= 6.0.0)
-
net8.0
- Castle.Core (>= 5.0.0)
- Microsoft.Extensions.DependencyInjection (>= 6.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
6.0.0 | 131 | 3/16/2024 |
5.0.0 | 170 | 11/24/2023 |
4.1.0 | 143 | 6/14/2023 |
4.0.0 | 156 | 6/11/2023 |
3.2.0 | 163 | 6/5/2023 |
3.1.0 | 147 | 5/28/2023 |
3.0.0 | 148 | 5/25/2023 |
2.1.2 | 144 | 5/22/2023 |
2.1.1 | 481 | 2/20/2022 |
2.1.0 | 445 | 2/12/2022 |
2.0.0 | 440 | 2/6/2022 |
1.3.0 | 312 | 11/27/2021 |
1.2.0 | 405 | 4/13/2021 |
1.1.0 | 356 | 3/16/2021 |
- Removed explicit .net 7.0 support
- Added explicit .net 8.0 support