Skip to content

Keyed Services

SourceGen.Ioc supports keyed service registration with Key and KeyType.
Support keyed service injecting with [FromKeyedServices], [ServiceKey] and [IocInject].

String Keys

csharp
public interface ICache;

[IocRegister<ICache>(Key = "memory")]
internal class MemoryCache : ICache;

[IocRegister<ICache>(Key = "distributed")]
internal class DistributedCache : ICache;
Generated Code
csharp
// <auto-generated/>
services.AddKeyedSingleton<global::MyNamespace.MemoryCache, global::MyNamespace.MemoryCache>("memory");
services.AddKeyedSingleton<global::MyNamespace.ICache>("memory", (global::System.IServiceProvider sp, object? key) => sp.GetRequiredKeyedService<global::MyNamespace.MemoryCache>(key));
services.AddKeyedSingleton<global::MyNamespace.DistributedCache, global::MyNamespace.DistributedCache>("distributed");
services.AddKeyedSingleton<global::MyNamespace.ICache>("distributed", (global::System.IServiceProvider sp, object? key) => sp.GetRequiredKeyedService<global::MyNamespace.DistributedCache>(key));

Enum Keys

csharp
public enum CacheType { Memory, Distributed }

[IocRegister<ICache>(Key = CacheType.Memory)]
internal class MemoryCache : ICache;

[IocRegister<ICache>(Key = CacheType.Distributed)]
internal class DistributedCache : ICache;
Generated Code
csharp
// <auto-generated/>
services.AddKeyedSingleton<global::MyNamespace.MemoryCache, global::MyNamespace.MemoryCache>(global::MyNamespace.CacheType.Memory);
services.AddKeyedSingleton<global::MyNamespace.ICache>(global::MyNamespace.CacheType.Memory, (global::System.IServiceProvider sp, object? key) => sp.GetRequiredKeyedService<global::MyNamespace.MemoryCache>(key));
services.AddKeyedSingleton<global::MyNamespace.DistributedCache, global::MyNamespace.DistributedCache>(global::MyNamespace.CacheType.Distributed);
services.AddKeyedSingleton<global::MyNamespace.ICache>(global::MyNamespace.CacheType.Distributed, (global::System.IServiceProvider sp, object? key) => sp.GetRequiredKeyedService<global::MyNamespace.DistributedCache>(key));

C# Expression Keys

Use KeyType.Csharp for compile-time expressions:

csharp
public static class CacheKeys
{
    public static readonly Guid Primary = Guid.CreateVersion7();
}

[IocRegister<ICache>(Key = nameof(CacheKeys.Primary), KeyType = KeyType.Csharp)]
internal class PrimaryCache : ICache;
Generated Code
csharp
// <auto-generated/>
services.AddKeyedSingleton<global::MyNamespace.PrimaryCache, global::MyNamespace.PrimaryCache>(global::MyNamespace.CacheKeys.Primary);
services.AddKeyedSingleton<global::MyNamespace.ICache>(global::MyNamespace.CacheKeys.Primary, (global::System.IServiceProvider sp, object? key) => sp.GetRequiredKeyedService<global::MyNamespace.PrimaryCache>(key));

Injecting Keyed Services

Constructor Injection with [IocInject]

Use [IocInject] to inject keyed services. This will generate factory method registration:

csharp
[IocRegister<IMyService>]
internal class MyService([IocInject("memory")] ICache cache) : IMyService
{
    private readonly ICache cache = cache;
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
    var p0 = sp.GetRequiredKeyedService<global::MyNamespace.ICache>("memory");
    var s0 = new global::MyNamespace.MyService(p0);
    return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

TIP

If you don't need KeyType.Csharp, use [FromKeyedServices] to align with MS.E.DI. See Using [FromKeyedServices].

Property Injection

csharp
[IocRegister<IMyService>]
internal class MyService : IMyService
{
    [IocInject("distributed")]
    public ICache Cache { get; init; } = null!;
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
    var s0_p0 = sp.GetRequiredKeyedService<global::MyNamespace.ICache>("distributed");
    var s0 = new global::MyNamespace.MyService() { Cache = s0_p0 };
    return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

Method Injection

csharp
[IocRegister<IMyService>]
internal class MyService : IMyService
{
    private ICache cache = null!;

    [IocInject]
    public void Initialize([IocInject("memory")] ICache cache)
    {
        this.cache = cache;
    }
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
    var s0_m0 = sp.GetRequiredKeyedService<global::MyNamespace.ICache>("memory");
    var s0 = new global::MyNamespace.MyService();
    s0.Initialize(s0_m0);
    return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

Using [FromKeyedServices]

You can also use the standard [FromKeyedServices] attribute from Microsoft.Extensions.DependencyInjection.

NOTE

[FromKeyedServices] is natively handled by MS.E.DI, so the generator uses simple type-based registration instead of factory methods.

csharp
[IocRegister<IMyService>]
internal class MyService([FromKeyedServices("memory")] ICache cache) : IMyService
{
    private readonly ICache cache = cache;
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService, global::MyNamespace.MyService>();
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

Difference from [IocInject]

[IocInject] attribute requires factory method registration because it's a SourceGen.Ioc-specific feature that MS.E.DI doesn't recognize:

csharp
[IocRegister<IMyService>]
internal class MyService([IocInject("memory")] ICache cache) : IMyService
{
    private readonly ICache cache = cache;
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
    var p0 = sp.GetRequiredKeyedService<global::MyNamespace.ICache>("memory");
    var s0 = new global::MyNamespace.MyService(p0);
    return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

Using [Inject] from Microsoft.AspNetCore.Components

You can also use any attribute that name is [Inject], for example Microsoft.AspNetCore.Components.InjectAttribute:

csharp
[IocRegister<IMyService>]
internal class MyService : IMyService
{
    [Inject(Key = "memory")]
    public ICache Cache { get; init; } = null!;
}
Generated Code
csharp
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
    var s0_p0 = sp.GetRequiredKeyedService<global::MyNamespace.ICache>("memory");
    var s0 = new global::MyNamespace.MyService() { Cache = s0_p0 };
    return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());

Using [ServiceKey]

You can use [ServiceKey] attribute to inject the key from service registration:

csharp
[IocRegister(Key = "Key")]
public class KeyService
{
    [IocInject]
    public void Initialize([ServiceKey] string key)
    {
        Console.WriteLine($"Service Key: {key}");
    }
}
Generated Code
csharp
// <auto-generated/>
services.AddKeyedTransient<global::MyNamespace.KeyService>("Key", (global::System.IServiceProvider sp, object? key) =>
{
    var s0_m0 = "Key";
    var s0 = new global::MyNamespace.KeyService();
    s0.Initialize(s0_m0);
    return s0;
});

Diagnostics

IDSeverityDescription
SGIOC006WarningBoth [FromKeyedServices] and [IocInject] are applied to the same parameter. [FromKeyedServices] takes precedence.
SGIOC013Error[ServiceKey] parameter type does not match the registered key type from [IocRegister] or [IocRegisterFor].
SGIOC014Warning[ServiceKey] is applied to a parameter, but no Key is specified in [IocRegister] or [IocRegisterFor].
SGIOC015WarningInjected KeyValuePair<K, V>/dictionary key type K is incompatible with the registered keyed services for V.

← Back to Overview

Released under the MIT License.