VDT.Core.DependencyInjection 2.1.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package VDT.Core.DependencyInjection --version 2.1.2
NuGet\Install-Package VDT.Core.DependencyInjection -Version 2.1.2
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="2.1.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add VDT.Core.DependencyInjection --version 2.1.2
#r "nuget: VDT.Core.DependencyInjection, 2.1.2"
#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=2.1.2

// Install VDT.Core.DependencyInjection as a Cake Tool
#tool nuget:?package=VDT.Core.DependencyInjection&version=2.1.2

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
  • 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 appropriate ServiceLifetime for a given service type and implementation type
  • UseDefaultServiceLifetime sets the default ServiceLifetime to use if no ServiceLifetimeProvider was provided or it did not return 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

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 interface
  • InterfaceByName 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
  • CreateGenericInterfaceTypeProvider generates a ServiceTypeProvider 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 type
  • Attributes.ScopedServiceAttribute marks a service to be registered as a scoped service with the supplied implementation type
  • Attributes.SingletoncopedServiceAttribute marks a service to be registered as a singleton service with the supplied implementation type
  • Attributes.TransientServiceImplementationAttribute marks the implementation to be registered as a transient service under the supplied service type
  • Attributes.ScopedServiceImplementationAttribute marks the implementation to be registered as a scoped service under the supplied service type
  • Attributes.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 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)
            .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 Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  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 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 is compatible. 
.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 96 3/16/2024
5.0.0 148 11/24/2023
4.1.0 130 6/14/2023
4.0.0 131 6/11/2023
3.2.0 142 6/5/2023
3.1.0 119 5/28/2023
3.0.0 127 5/25/2023
2.1.2 123 5/22/2023
2.1.1 460 2/20/2022
2.1.0 418 2/12/2022
2.0.0 418 2/6/2022
1.3.0 285 11/27/2021
1.2.0 379 4/13/2021
1.1.0 345 3/16/2021

- Moved project to separate repository
- Updated dependencies
- Added package icon