AttributeDependencyInjection 1.0.0

dotnet add package AttributeDependencyInjection --version 1.0.0                
NuGet\Install-Package AttributeDependencyInjection -Version 1.0.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="AttributeDependencyInjection" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AttributeDependencyInjection --version 1.0.0                
#r "nuget: AttributeDependencyInjection, 1.0.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 AttributeDependencyInjection as a Cake Addin
#addin nuget:?package=AttributeDependencyInjection&version=1.0.0

// Install AttributeDependencyInjection as a Cake Tool
#tool nuget:?package=AttributeDependencyInjection&version=1.0.0                

<img height="30px" src="./.assets/icon_64.png" alt="Attribute Dependency Injection"></img> Attribute Dependency Injection (DI)

This project provides a set of extensions to the IServiceCollection for registering services using custom attributes.

  • Attribute-Based Injection: Register services by decorating classes and structs with custom attributes.
  • Dynamic Service Registration: Allows methods decorated with special attributes to be invoked during the registration process.
  • Exclusions: Exclude specific services or implementations from being registered.

How to Use

Add <code>DependencyAssemblyAttribute</code> for Discoverability

By default, only assemblies with the <code>DependencyAssemblyAttribute</code> will be scanned for attributed services (this behavior can be changed through the startup options).

.NET Core and later Add the attribute through the project's <code>.csproj</code> file:

<ItemGroup>
    <AssemblyAttribute Include="AttributeDI.Attributes.DependencyAssemblyAttribute" />
</ItemGroup>

.NET Framework Add the attribute in the <code>AssemblyInfo.cs</code> file:

[assembly: DependencyAssembly]

Defining Services with Attributes

Services are defined using attributes that indicate how they should be registered with the DI container. The example below shows their basic usage:

using AttributeDI.Attributes;
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel;

namespace AttributedDI.ConsoleExample.Services
{
    [ServiceRegistration] // Registers the FileService as a singleton service.
    public sealed class FileService
    {
        public FileService()
        {
        }
    }

    public interface IResponderService
    {
        FileService Files { get; }
        void Respond();
    }

    [ServiceRegistration(typeof(IResponderService))] // Registers the ResponderService as the implementation with
                                                     // IResponderService as the service type.
    file sealed class ResponderService : IResponderService
    {
        public FileService Files { get; }

        public ResponderService(FileService fs)
        {
            this.Files = fs;
        }

        public void Respond()
        {
            Console.WriteLine("Hello, World!");
        }
    }

    public interface IQuestion
    {
        string Value { get; }
    }

    [DynamicServiceRegistration] // Invokes a method decorated with DynamicServiceRegistrationMethodAttribute.
    public sealed class QuestionService
    {
        private readonly IQuestion _defaultQuestion;

        internal QuestionService(IQuestion defaultQuestion)
        {
            _defaultQuestion = defaultQuestion;
        }

        public string Ask(IQuestion? question)
        {
            return question is null ? _defaultQuestion.Value : question.Value;
        }

        [DynamicServiceRegistrationMethod]
        [EditorBrowsable(EditorBrowsableState.Never)]
        private static void AddToServices(IServiceCollection services)
        {
            services.AddSingleton(x =>
            {
                var question = x.GetRequiredService<IQuestion>();
                return new QuestionService(question);
            });
        }

        [ServiceStructRegistration(typeof(IQuestion), Lifetime = ServiceLifetime.Transient)]
        internal readonly struct Question : IQuestion
        {
            public string Value => "Hello, World!";

            public Question()
            {
            }
        }
    }

    [ServiceRegistration(typeof(IResponderService))]
    public sealed class ExcludeThisService : IResponderService
    {
        public ExcludeThisService(FileService fs)
        {
            this.Files = fs;
        }

        public FileService Files { get; }

        public void Respond()
        {
            throw new NotImplementedException();
        }
    }
}

Call the AddAttributedServices Method

To add the attributed services into your application's startup routine, use one of the overloads for <code>AttributeDI.AttributeDIExtensions.AddAttributedServices()</code>

using AttributeDI.Attributes;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using Microsoft.Extensions.Configuration;

public class Startup
{
    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        // Register services using assemblies and configuration
        services.AddAttributedServices(new[] { Assembly.GetExecutingAssembly() }, configuration);

        // Or configure options with an action
        services.AddAttributedServices(options =>
        {
            options.Configuration = configuration;
            options.IncludeNonAttributedAssembliesInScan = true;
        });
    }
}

Excluding Services

During the initial registration setup, services can be excluded from being registered for any reason. Exclusions can be added by the service or the implementation type.

using AttributeDI.Attributes;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using Microsoft.Extensions.Configuration;

public class Startup
{
    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        // Exclude service(s) for testing
        services.AddAttributedServices(options =>
        {
            options.AddExclusions(x => 
            {
                x.Add<ExcludeThisService>()
                 .Add(typeof(TestCollection<>))
                 .Add<ITestInterface>();
            });
        });
    }
}

Attributes

<code>ServiceRegistrationAttribute</code>

Indicates that the decorated class should be registered as a service. The lifetime of the service can be specified through the attribute property <code>Lifetime</code>.


// Registers a singleton service and implementation type of MyLoneService
[ServiceRegistration]
public sealed class MyLoneService
{
    // Implementation
}

// -- or --

// Registers a service type 'IServiceType' with the implementation of MyService.
[ServiceRegistration(typeof(IServiceType), Lifetime = ServiceLifetime.Scoped)]
internal sealed class MyService : IServiceType
{
    // Implementation
}

Generic types with this attribute will be registered with their generic type definition.

[ServiceRegistration(typeof(IServiceType<>), Lifetime = ServiceLifetime.Scoped)]
public sealed class MyService<T> : IServiceType<T>
{
    // Implementation
}

<code>ServiceStructRegistrationAttribute</code>

Registers a struct implementation using the specified interface service type.

[ServiceStructRegistration(typeof(IServiceType), Lifetime = ServiceLifetime.Transient)]
public struct MyServiceStruct : IServiceType
{
    // Implementation
}

<code>DynamicServiceRegistrationAttribute</code>

Indicates that a method decorated with the <code>DynamicServiceRegistrationMethodAttribute</code> should be invoked during the registration process to dynamically add services.

[DynamicServiceRegistration]
public sealed class DynamicService
{
    private readonly IOtherService _other;

    private DynamicService(IOtherService other)
    {
        _other = other;
    }

    [DynamicServiceRegistrationMethod]
    private static void AddToServices(IServiceCollection services)
    {
        services.AddSingleton(x =>
        {
            var other = x.GetRequiredService<IOtherService>();
            return new DynamicService(other);
        });
    }
}

Optionally, if the application's <code>IConfiguration</code> is provided to the startup options, you can specify a different overload:

[DynamicServiceRegistration]
public sealed class DynamicService
{
    [DynamicServiceRegistrationMethod]
    private static void AddToServices(IServiceCollection services, IConfiguration configuration)
    {
        services.AddOptions<DynamicService>()
                .Bind(configuration);
    }
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  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
1.0.0 94 7/28/2024