Skip to content

Commit 8f05d9b

Browse files
authored
Merge pull request #1490 from autofac/feature/issue-1327
Add GetRegistrationId extension to expose a registration's unique ID (#1327)
2 parents 0e724c2 + 40fe97d commit 8f05d9b

3 files changed

Lines changed: 134 additions & 1 deletion

File tree

default.proj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project DefaultTargets="All" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
33
<PropertyGroup>
44
<!-- Increment the overall semantic version here. -->
5-
<Version>9.1.1</Version>
5+
<Version>9.2.0</Version>
66
<SolutionName>Autofac</SolutionName>
77
<Configuration Condition="'$(Configuration)'==''">Release</Configuration>
88
<ArtifactDirectory>$([System.IO.Path]::Combine($(MSBuildProjectDirectory),"artifacts"))</ArtifactDirectory>

src/Autofac/RegistrationExtensions.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,4 +780,51 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TStyle>
780780
var tags = new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag }.Concat(lifetimeScopeTags).ToArray();
781781
return registration.InstancePerMatchingLifetimeScope(tags);
782782
}
783+
784+
/// <summary>
785+
/// Gets the unique <see cref="Guid"/> identity assigned to a single-component registration.
786+
/// </summary>
787+
/// <typeparam name="TLimit">Registration limit type.</typeparam>
788+
/// <typeparam name="TActivatorData">Activator data type.</typeparam>
789+
/// <param name="registration">The registration whose identity to retrieve.</param>
790+
/// <returns>
791+
/// The <see cref="Guid"/> that uniquely identifies this registration. This is the same value
792+
/// that will appear on the resulting <see cref="Core.IComponentRegistration.Id"/> after the
793+
/// container is built.
794+
/// </returns>
795+
/// <exception cref="ArgumentNullException">
796+
/// Thrown if <paramref name="registration" /> is <see langword="null" />.
797+
/// </exception>
798+
/// <remarks>
799+
/// <para>
800+
/// Each single-component registration (created via <see cref="RegisterType{TImplementer}(ContainerBuilder)"/>,
801+
/// <see cref="Register{T}(ContainerBuilder, Func{IComponentContext, T})"/>, or
802+
/// <see cref="RegisterInstance{T}(ContainerBuilder, T)"/>) is assigned a stable <see cref="Guid"/>
803+
/// at the time the registration builder is created. This ID flows through unchanged to
804+
/// <see cref="Core.IComponentRegistration.Id"/> when the container is built.
805+
/// </para>
806+
/// <para>
807+
/// A common use case is to capture the registration ID before building the container and use
808+
/// it as a key in <see cref="ContainerBuilder.Properties"/> to associate per-registration
809+
/// state or metadata, then look that state up at resolve time via
810+
/// <see cref="Core.IComponentRegistration.Id"/>.
811+
/// </para>
812+
/// <para>
813+
/// This method is only available for single-component registrations
814+
/// (<see cref="Builder.SingleRegistrationStyle"/>). Multi-component registrations such as
815+
/// open-generic registrations (via <c>RegisterGeneric</c>), assembly-scanning registrations,
816+
/// adapters, and decorators do not have a single stable identity and this method is not
817+
/// callable on them — attempting to do so results in a compile-time error.
818+
/// </para>
819+
/// </remarks>
820+
public static Guid GetRegistrationId<TLimit, TActivatorData>(
821+
this IRegistrationBuilder<TLimit, TActivatorData, SingleRegistrationStyle> registration)
822+
{
823+
if (registration == null)
824+
{
825+
throw new ArgumentNullException(nameof(registration));
826+
}
827+
828+
return registration.RegistrationStyle.Id;
829+
}
783830
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) Autofac Project. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
using Autofac.Builder;
5+
using Autofac.Core;
6+
7+
namespace Autofac.Test.Builder;
8+
9+
public class GetRegistrationIdTests
10+
{
11+
[Fact]
12+
public void GetRegistrationId_NullRegistration_ThrowsArgumentNullException()
13+
{
14+
// Issue #1327
15+
IRegistrationBuilder<object, SimpleActivatorData, SingleRegistrationStyle> registration = null;
16+
Assert.Throws<ArgumentNullException>(() => registration.GetRegistrationId());
17+
}
18+
19+
[Fact]
20+
public void GetRegistrationId_RegisterType_MatchesBuiltComponentRegistrationId()
21+
{
22+
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
23+
var cb = new ContainerBuilder();
24+
var rb = cb.RegisterType<MyComponent>();
25+
var capturedId = rb.GetRegistrationId();
26+
var container = cb.Build();
27+
28+
Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
29+
Assert.Equal(capturedId, cr.Id);
30+
}
31+
32+
[Fact]
33+
public void GetRegistrationId_RegisterDelegate_MatchesBuiltComponentRegistrationId()
34+
{
35+
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
36+
var cb = new ContainerBuilder();
37+
var rb = cb.Register(_ => new MyComponent());
38+
var capturedId = rb.GetRegistrationId();
39+
var container = cb.Build();
40+
41+
Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
42+
Assert.Equal(capturedId, cr.Id);
43+
}
44+
45+
[Fact]
46+
public void GetRegistrationId_RegisterInstance_MatchesBuiltComponentRegistrationId()
47+
{
48+
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
49+
var instance = new MyComponent();
50+
var cb = new ContainerBuilder();
51+
var rb = cb.RegisterInstance(instance);
52+
var capturedId = rb.GetRegistrationId();
53+
var container = cb.Build();
54+
55+
Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
56+
Assert.Equal(capturedId, cr.Id);
57+
}
58+
59+
[Fact]
60+
public void GetRegistrationId_CalledTwice_ReturnsSameGuid()
61+
{
62+
// Issue #1327 - The ID is stable across multiple calls on the same builder.
63+
var cb = new ContainerBuilder();
64+
var rb = cb.RegisterType<MyComponent>();
65+
66+
var id1 = rb.GetRegistrationId();
67+
var id2 = rb.GetRegistrationId();
68+
69+
Assert.Equal(id1, id2);
70+
}
71+
72+
[Fact]
73+
public void GetRegistrationId_TwoDistinctRegistrations_ReturnDifferentGuids()
74+
{
75+
// Issue #1327 - Each registration gets its own unique ID.
76+
var cb = new ContainerBuilder();
77+
var rb1 = cb.RegisterType<MyComponent>();
78+
var rb2 = cb.Register(_ => new MyComponent());
79+
80+
Assert.NotEqual(rb1.GetRegistrationId(), rb2.GetRegistrationId());
81+
}
82+
83+
private class MyComponent
84+
{
85+
}
86+
}

0 commit comments

Comments
 (0)