Skip to content
dalton-baker edited this page Nov 23, 2025 · 13 revisions

DepRegAttributes

Register services with attributes. Skip manual registration in Program.cs!


Quick Start

Attributes for registration:

[RegisterTransient]
[RegisterScoped]
[RegisterSingleton]

Register all attributed services:

serviceCollection.AddByAttribute();
serviceCollection.AddByAttribute(assembly); // Only from specific assembly

Usage Examples

1. Basic Registration

[RegisterTransient]
public class ExampleService { }
// Equivalent: serviceCollection.AddTransient<ExampleService>();

If your class implements an interface with a matching name, it will be registered as that interface:

[RegisterTransient]
public class ExampleService : IExampleService { }
// Equivalent: serviceCollection.AddTransient<IExampleService, ExampleService>();

Note: Explicit service types in the attribute override this behavior.

2. Explicit Service Types

[RegisterTransient<IAnotherExampleService>]
public class ExampleService : ExampleServiceBase, IExampleService, IAnotherExampleService { }
// Equivalent: serviceCollection.AddTransient<IAnotherExampleService, ExampleService>();

Register with multiple service types:

[RegisterTransient<ExampleServiceBase, IExampleService, IAnotherExampleService>]
public class ExampleService : ExampleServiceBase, IExampleService, IAnotherExampleService { }
// Equivalent:
// serviceCollection.AddTransient<ExampleServiceBase, ExampleService>();
// serviceCollection.AddTransient<IExampleService, ExampleService>();
// serviceCollection.AddTransient<IAnotherExampleService, ExampleService>();

Or use multiple attributes:

[RegisterTransient<ExampleServiceBase>]
[RegisterTransient<IExampleService>]
[RegisterTransient<IAnotherExampleService>]
public class ExampleService : ExampleServiceBase, IExampleService, IAnotherExampleService { }
// Equivalent: One registration per attribute

C# < 11: Use type arguments instead of generics:

[RegisterTransient(typeof(IExampleService), typeof(IAnotherExampleService))]
public class ExampleService : ExampleServiceBase, IExampleService, IAnotherExampleService { }

3. Singleton & Scoped Registration

For each attribute, only one object is constructed for singleton or scoped services:

[RegisterSingleton<IExampleService, IAnotherExampleService>]
public class ExampleService : IExampleService, IAnotherExampleService { }
// Equivalent:
// serviceCollection.AddSingleton<IExampleService, ExampleService>();
// serviceCollection.AddSingleton(sp => (IAnotherExampleService)sp.GetRequiredService<IExampleService>());

Both interfaces resolve to the same instance.

Multiple attributes = different instances:

[RegisterSingleton<IExampleService>]
[RegisterSingleton<IAnotherExampleService>]
public class ExampleService : IExampleService, IAnotherExampleService { }
// Equivalent: Separate singleton for each service type

Registering Hosted Services

To register a hosted service, use:

[RegisterSingleton<IHostedService>]
public class MyWorker : IHostedService { }
// Equivalent: services.AddHostedService<MyWorker>()

Advanced Features

Registration Tags

Tags allow conditional registration. Tags must be constants (string, enum, number):

serviceCollection.AddByAttribute("Example");
serviceCollection.AddByAttribute(14);
serviceCollection.AddByAttribute(ExampleEnum.ExampleValue);

Set tags via the attribute:

[RegisterTransient(Tag = "Example")]
public class ExampleService { }
// Only registered if tag matches

Call AddByAttribute for each tag:

serviceCollection.AddByAttribute(); // Untagged
serviceCollection.AddByAttribute(ExampleEnum.ExampleValue);
serviceCollection.AddByAttribute(14);

Keyed Services (Not available in v3)

Read more: .NET 8 Release Notes

Register a keyed service:

[RegisterTransient(Key = "Example")]
public class ExampleService { }
// Equivalent: serviceCollection.AddKeyedTransient<ExampleService>("Example");

Unbound Generics

Register a generic class as an unbound generic:

[RegisterTransient]
public class ExampleService<T> { }
// Equivalent: serviceCollection.AddTransient(typeof(ExampleService<>));

Explicit interface registration for unbound generics:

[RegisterTransient(typeof(IExampleService<>))]
public class ExampleService<T> : IExampleService<T> { }
// Equivalent: serviceCollection.AddTransient(typeof(IExampleService<>), typeof(ExampleService<>));

Note: Use typeof() for unbound generics. No analyzer support (runtime errors only).