Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion default.proj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project DefaultTargets="All" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Current">
<PropertyGroup>
<!-- Increment the overall semantic version here. -->
<Version>9.1.1</Version>
<Version>9.2.0</Version>
<SolutionName>Autofac</SolutionName>
<Configuration Condition="'$(Configuration)'==''">Release</Configuration>
<ArtifactDirectory>$([System.IO.Path]::Combine($(MSBuildProjectDirectory),"artifacts"))</ArtifactDirectory>
Expand Down
47 changes: 47 additions & 0 deletions src/Autofac/RegistrationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -780,4 +780,51 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TStyle>
var tags = new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag }.Concat(lifetimeScopeTags).ToArray();
return registration.InstancePerMatchingLifetimeScope(tags);
}

/// <summary>
/// Gets the unique <see cref="Guid"/> identity assigned to a single-component registration.
/// </summary>
/// <typeparam name="TLimit">Registration limit type.</typeparam>
/// <typeparam name="TActivatorData">Activator data type.</typeparam>
/// <param name="registration">The registration whose identity to retrieve.</param>
/// <returns>
/// The <see cref="Guid"/> that uniquely identifies this registration. This is the same value
/// that will appear on the resulting <see cref="Core.IComponentRegistration.Id"/> after the
/// container is built.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="registration" /> is <see langword="null" />.
/// </exception>
/// <remarks>
/// <para>
/// Each single-component registration (created via <see cref="RegisterType{TImplementer}(ContainerBuilder)"/>,
/// <see cref="Register{T}(ContainerBuilder, Func{IComponentContext, T})"/>, or
/// <see cref="RegisterInstance{T}(ContainerBuilder, T)"/>) is assigned a stable <see cref="Guid"/>
/// at the time the registration builder is created. This ID flows through unchanged to
/// <see cref="Core.IComponentRegistration.Id"/> when the container is built.
/// </para>
/// <para>
/// A common use case is to capture the registration ID before building the container and use
/// it as a key in <see cref="ContainerBuilder.Properties"/> to associate per-registration
/// state or metadata, then look that state up at resolve time via
/// <see cref="Core.IComponentRegistration.Id"/>.
/// </para>
/// <para>
/// This method is only available for single-component registrations
/// (<see cref="Builder.SingleRegistrationStyle"/>). Multi-component registrations such as
/// open-generic registrations (via <c>RegisterGeneric</c>), assembly-scanning registrations,
/// adapters, and decorators do not have a single stable identity and this method is not
/// callable on them — attempting to do so results in a compile-time error.
/// </para>
/// </remarks>
public static Guid GetRegistrationId<TLimit, TActivatorData>(
this IRegistrationBuilder<TLimit, TActivatorData, SingleRegistrationStyle> registration)
{
if (registration == null)
{
throw new ArgumentNullException(nameof(registration));
}

return registration.RegistrationStyle.Id;
}
}
86 changes: 86 additions & 0 deletions test/Autofac.Test/Builder/GetRegistrationIdTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) Autofac Project. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Autofac.Builder;
using Autofac.Core;

namespace Autofac.Test.Builder;

public class GetRegistrationIdTests
{
[Fact]
public void GetRegistrationId_NullRegistration_ThrowsArgumentNullException()
{
// Issue #1327
IRegistrationBuilder<object, SimpleActivatorData, SingleRegistrationStyle> registration = null;
Assert.Throws<ArgumentNullException>(() => registration.GetRegistrationId());
}

[Fact]
public void GetRegistrationId_RegisterType_MatchesBuiltComponentRegistrationId()
{
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
var cb = new ContainerBuilder();
var rb = cb.RegisterType<MyComponent>();
var capturedId = rb.GetRegistrationId();
var container = cb.Build();

Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
Assert.Equal(capturedId, cr.Id);
}

[Fact]
public void GetRegistrationId_RegisterDelegate_MatchesBuiltComponentRegistrationId()
{
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
var cb = new ContainerBuilder();
var rb = cb.Register(_ => new MyComponent());
var capturedId = rb.GetRegistrationId();
var container = cb.Build();

Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
Assert.Equal(capturedId, cr.Id);
}

[Fact]
public void GetRegistrationId_RegisterInstance_MatchesBuiltComponentRegistrationId()
{
// Issue #1327 - The ID returned before build matches IComponentRegistration.Id after build.
var instance = new MyComponent();
var cb = new ContainerBuilder();
var rb = cb.RegisterInstance(instance);
var capturedId = rb.GetRegistrationId();
var container = cb.Build();

Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(MyComponent)), out var cr));
Assert.Equal(capturedId, cr.Id);
}

[Fact]
public void GetRegistrationId_CalledTwice_ReturnsSameGuid()
{
// Issue #1327 - The ID is stable across multiple calls on the same builder.
var cb = new ContainerBuilder();
var rb = cb.RegisterType<MyComponent>();

var id1 = rb.GetRegistrationId();
var id2 = rb.GetRegistrationId();

Assert.Equal(id1, id2);
}

[Fact]
public void GetRegistrationId_TwoDistinctRegistrations_ReturnDifferentGuids()
{
// Issue #1327 - Each registration gets its own unique ID.
var cb = new ContainerBuilder();
var rb1 = cb.RegisterType<MyComponent>();
var rb2 = cb.Register(_ => new MyComponent());

Assert.NotEqual(rb1.GetRegistrationId(), rb2.GetRegistrationId());
}

private class MyComponent
{
}
}
Loading