VDT.Core.DependencyInjection
3.1.0
See the version list below for details.
dotnet add package VDT.Core.DependencyInjection --version 3.1.0
NuGet\Install-Package VDT.Core.DependencyInjection -Version 3.1.0
<PackageReference Include="VDT.Core.DependencyInjection" Version="3.1.0" />
paket add VDT.Core.DependencyInjection --version 3.1.0
#r "nuget: VDT.Core.DependencyInjection, 3.1.0"
// Install VDT.Core.DependencyInjection as a Cake Addin #addin nuget:?package=VDT.Core.DependencyInjection&version=3.1.0 // Install VDT.Core.DependencyInjection as a Cake Tool #tool nuget:?package=VDT.Core.DependencyInjection&version=3.1.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
AddServiceTypeProvider
adds a method that returns service types for a given implementation type found in the assemblies- These methods must match the delegate method
ServiceTypeProvider
- It is possible to supply a
ServiceLifetimeProvider
that returns the appropriateServiceLifetime
for a given service type and implementation type
- These methods must match the delegate method
UseDefaultServiceLifetime
sets the defaultServiceLifetime
to use if noServiceLifetimeProvider
was provided or it did not return 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
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 type provider with a lifetime provider
.AddServiceTypeProvider(
serviceTypeProvider: implementationType => implementationType.GetInterfaces().Where(serviceType => serviceType.Assembly == implementationType.Assembly),
serviceLifetimeProvider: (serviceType, implementationType) => ServiceLifetime.Scoped
)
// Add a service type provider without a lifetime provider
.AddServiceTypeProvider(
serviceTypeProvider: implementationType => implementationType.GetInterfaces().Where(serviceType => serviceType.Assembly == implementationType.Assembly)
)
// 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 DefaultServiceTypeProviders
contains three ways to register services based on common conventions:
SingleInterface
returns the single interface if an implementation type implements exactly one interfaceInterfaceByName
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
CreateGenericInterfaceTypeProvider
generates aServiceTypeProvider
that finds generic types based on a generic type definition- This is useful if you implement generic interface types such request handlers, command handlers or query handlers
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 type providers
.AddServiceTypeProvider(
serviceTypeProvider: DefaultServiceTypeProviders.SingleInterface
)
.AddServiceTypeProvider(
serviceTypeProvider: DefaultServiceTypeProviders.InterfaceByName
)
.AddServiceTypeProvider(
serviceTypeProvider: DefaultServiceTypeProviders.CreateGenericInterfaceTypeProvider(typeof(IRequestHandler))
)
);
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// ...
}
}
Attribute-based service registration
The extension method Attributes.ServiceRegistrationOptionsExtensions.AddAttributeServiceTypeProviders
allows you to move registration for your services from
the Startup
class to the services themselves without using convention-based registration. 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 six attributes available:
Attributes.TransientServiceAttribute
marks a service to be registered as a transient service with the supplied implementation typeAttributes.ScopedServiceAttribute
marks a service to be registered as a scoped service with the supplied implementation typeAttributes.SingletoncopedServiceAttribute
marks a service to be registered as a singleton service with the supplied implementation typeAttributes.TransientServiceImplementationAttribute
marks the implementation to be registered as a transient service under the supplied service typeAttributes.ScopedServiceImplementationAttribute
marks the implementation to be registered as a scoped service under the supplied service typeAttributes.SingletonServiceImplementationAttribute
marks the implementation to be registered as a singleton service under 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 type 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 {
public void Foo() {
// ...
}
}
public interface IBar {
void Foo();
}
// Mark the implementation
[ScopedServiceImplementation(serviceType: typeof(Bar))]
public class Bar {
public void Foo() {
// ...
}
}
public class Startup {
public void ConfigureServices(IServiceCollection services) {
// Register using options
services.AddServices(setupAction: options => options
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddAttributeServiceTypeProviders()
);
// 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 ServiceTypeProvider
implementations.
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)
.AddServiceTypeProvider(
serviceTypeProvider: DefaultServiceTypeProviders.InterfaceByName
)
.UseDecoratorServiceRegistrar(setupAction: options => options.AddDecorator<LogDecorator>(predicate: method => method.Name == "Foo")
);
// Register services using attributes
services.AddServices(options => options
.AddAssembly(assembly: typeof(Startup).Assembly)
.AddServiceTypeProvider(
serviceTypeProvider: DefaultServiceTypeProviders.InterfaceByName
)
.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 is compatible. 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 was computed. 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)
-
net7.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 | 135 | 3/16/2024 |
5.0.0 | 174 | 11/24/2023 |
4.1.0 | 147 | 6/14/2023 |
4.0.0 | 160 | 6/11/2023 |
3.2.0 | 168 | 6/5/2023 |
3.1.0 | 151 | 5/28/2023 |
3.0.0 | 152 | 5/25/2023 |
2.1.2 | 148 | 5/22/2023 |
2.1.1 | 485 | 2/20/2022 |
2.1.0 | 449 | 2/12/2022 |
2.0.0 | 444 | 2/6/2022 |
1.3.0 | 316 | 11/27/2021 |
1.2.0 | 409 | 4/13/2021 |
1.1.0 | 360 | 3/16/2021 |
- Removed unnecessary decorator proxy generation when no decorators are applied to a service
- Made it possible to register a service as itself so long as no decorators are applied
- Marked the Add... extension methods for decorators that have an explicit service implementation type parameter as obsolete since they offered no benefits over registering an implementation as its own type