Skip to content

Basic Usage

SourceGen.Ioc provides two main approaches for service registration:

  1. Non-intrusive[IocRegisterFor] registers types externally, keeping your service code attribute-free.
  2. Direct annotation[IocRegister] marks the class at its declaration (best for infrastructure types you own).

TIP

Prefer [IocRegisterFor] for domain/business types and [IocRegister] for infrastructure types. This keeps your domain layer free of DI framework concerns.

Registering External Types (Non-Intrusive)

Use [IocRegisterFor<T>] (generic) or [IocRegisterFor] (non-generic) to register types without modifying their source code:

csharp
// In a dedicated registration file — service types stay attribute-free
[assembly: IocRegisterFor<UserService>(ServiceLifetime.Scoped, ServiceTypes = [typeof(IUserService)])]
[assembly: IocRegisterFor<OrderService>(ServiceLifetime.Scoped, ServiceTypes = [typeof(IOrderService)])]

// Or on a marker class
[IocRegisterFor<UserService>(ServiceLifetime.Scoped, ServiceTypes = [typeof(IUserService)])]
[IocRegisterFor<OrderService>(ServiceLifetime.Scoped, ServiceTypes = [typeof(IOrderService)])]
public class RegistrationMarker;

NOTE

Generic attributes require C# 11+. If your project targets an older language version, use the non-generic form: [IocRegisterFor(typeof(UserService))].

IocRegisterFor supports the same options as IocRegister (Key, KeyType, Tags, Decorators, Factory, Instance, and lifetime settings).

Generated Code
csharp
services.AddScoped<UserService, UserService>();
services.AddScoped<IUserService>((global::System.IServiceProvider sp) => sp.GetRequiredService<UserService>());
services.AddScoped<OrderService, OrderService>();
services.AddScoped<IOrderService>((global::System.IServiceProvider sp) => sp.GetRequiredService<OrderService>());

Simple Registration (Direct Annotation)

Mark a class with [IocRegister] to register it directly:

csharp
public interface IMyService;

[IocRegister<IMyService>]
internal class MyService : IMyService;
// Or non-generic version
[IocRegister(typeof(IMyService))]
internal class MyService : IMyService;
Generated Code
csharp
services.AddTransient<MyService, MyService>();
services.AddTransient<IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<MyService>());

Specifying Lifetime

csharp
// Transient (default)
[IocRegister<IService>]
internal class TransientService : IService;

// Singleton
[IocRegister<IService>(ServiceLifetime.Singleton)]
internal class SingletonService : IService;

// Scoped
[IocRegister<IService>(ServiceLifetime.Scoped)]
internal class ScopedService : IService;
Generated Code
csharp
services.AddTransient<TransientService, TransientService>();
services.AddTransient<IService>((global::System.IServiceProvider sp) => sp.GetRequiredService<TransientService>());

services.AddSingleton<SingletonService, SingletonService>();
services.AddSingleton<IService>((global::System.IServiceProvider sp) => sp.GetRequiredService<SingletonService>());

services.AddScoped<ScopedService, ScopedService>();
services.AddScoped<IService>((global::System.IServiceProvider sp) => sp.GetRequiredService<ScopedService>());

Multiple Service Types

Register a class under multiple service types:

csharp
// Using generic attribute parameters
[IocRegister<IService1, IService2>]
internal class MultiService : IService1, IService2;

// Or using params
[IocRegister(typeof(IService1), typeof(IService2))]
internal class MultiService : IService1, IService2;
Generated Code
csharp
services.AddTransient<MultiService, MultiService>();
services.AddTransient<IService1>((global::System.IServiceProvider sp) => sp.GetRequiredService<MultiService>());
services.AddTransient<IService2>((global::System.IServiceProvider sp) => sp.GetRequiredService<MultiService>());

Register All Interfaces/Base Classes

csharp
// Register all implemented interfaces
[IocRegister(RegisterAllInterfaces = true)]
internal class MyService : IService1, IService2, IDisposable;

// Register all base classes
[IocRegister(RegisterAllBaseClasses = true)]
internal class DerivedService : BaseService;
Generated Code
csharp
// RegisterAllInterfaces
services.AddSingleton<MyService, MyService>();
services.AddSingleton<IService1>((global::System.IServiceProvider sp) => sp.GetRequiredService<MyService>());
services.AddSingleton<IService2>((global::System.IServiceProvider sp) => sp.GetRequiredService<MyService>());
services.AddSingleton<IDisposable>((global::System.IServiceProvider sp) => sp.GetRequiredService<MyService>());

// RegisterAllBaseClasses
services.AddSingleton<DerivedService, DerivedService>();
services.AddSingleton<BaseService>((global::System.IServiceProvider sp) => sp.GetRequiredService<DerivedService>());

Usage

csharp
// In your startup/program
var services = new ServiceCollection();
services.AddMyProject(); // Generated extension method

Diagnostics

IDSeverityDescription
SGIOC001Error[IocRegister] or [IocRegisterFor] cannot be applied to private or abstract classes.
SGIOC011WarningDuplicated registration detected for the same implementation type, same key, and at least one matching tag.

Custom Method Name

Use the SourceGenIocName MSBuild property to customize the generated method name:

xml
<PropertyGroup>
    <SourceGenIocName>MyApp</SourceGenIocName>
</PropertyGroup>

This generates:

csharp
// Generated extension method with custom name
services.AddMyApp();

// Tag methods also use the custom name
services.AddMyApp_Tag1();

If not specified, the assembly name is used as the default method name.


← Back to Overview

Released under the MIT License.