VDT.Core.DependencyInjection 4.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package VDT.Core.DependencyInjection --version 4.1.0                
NuGet\Install-Package VDT.Core.DependencyInjection -Version 4.1.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VDT.Core.DependencyInjection" Version="4.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add VDT.Core.DependencyInjection --version 4.1.0                
#r "nuget: VDT.Core.DependencyInjection, 4.1.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install VDT.Core.DependencyInjection as a Cake Addin
#addin nuget:?package=VDT.Core.DependencyInjection&version=4.1.0

// Install VDT.Core.DependencyInjection as a Cake Tool
#tool nuget:?package=VDT.Core.DependencyInjection&version=4.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 services
  • AddAssemblies 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 desired ServiceLifetime
  • UseDefaultServiceLifetime sets the default ServiceLifetime to use if the found ServiceRegistration does not include a ServiceLifetime
  • 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
  • Please note that the AddServiceTypeProvider methods have been deprecated since they are being replaced by AddServiceRegistrationProvider

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 interface
  • CreateInterfaceByNameProvider 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
  • 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

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 transient
  • Attributes.ScopedAttribute marks a service to be registered as scoped
  • Attributes.SingletonServiceAttribute marks a service to be registered as singleton
  • Attributes.TransientServiceAttribute marks a service to be registered as transient with the supplied implementation type
  • Attributes.ScopedServiceAttribute marks a service to be registered as scoped with the supplied implementation type
  • Attributes.SingletonScopedServiceAttribute marks a service to be registered as singleton with the supplied implementation type
  • Attributes.TransientServiceImplementationAttribute marks a service implementation to be registered as transient for the supplied service type
  • Attributes.ScopedServiceImplementationAttribute marks a service implementation to be registered as scoped for the supplied service type
  • Attributes.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 {
    public void Foo() {
        // ...
    }
}

public interface IBar {
    void Foo();
}

// Mark the implementation
[ScopedServiceImplementation(serviceType: typeof(IBar))]
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)
            .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 method
  • AfterExecute allows you to execute code after execution of the decorated method
  • OnError 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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 133 3/16/2024
5.0.0 172 11/24/2023
4.1.0 145 6/14/2023
4.0.0 158 6/11/2023
3.2.0 165 6/5/2023
3.1.0 149 5/28/2023
3.0.0 150 5/25/2023
2.1.2 146 5/22/2023
2.1.1 483 2/20/2022
2.1.0 447 2/12/2022
2.0.0 442 2/6/2022
1.3.0 314 11/27/2021
1.2.0 407 4/13/2021
1.1.0 358 3/16/2021

- Added attributes that don't need an additional type for more easily registering a service as itself