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
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,21 @@
<PackageVersion Include="Grpc.StatusProto" Version="2.76.0" />
<PackageVersion Include="Grpc.Tools" Version="2.76.0" />
<PackageVersion Include="HtmlTags" Version="9.0.0" />
<PackageVersion Include="JasperFx" Version="2.8.2" />
<PackageVersion Include="JasperFx.Events" Version="2.8.2" />
<PackageVersion Include="JasperFx.Events.SourceGenerator" Version="2.8.2" />
<PackageVersion Include="JasperFx" Version="2.9.10" />
<PackageVersion Include="JasperFx.Events" Version="2.9.10" />
<PackageVersion Include="JasperFx.Events.SourceGenerator" Version="2.9.10" />
<!-- RuntimeCompiler is on its own 5.x line (the Roslyn compiler package) — not the 2.1.x
family; it stays at 5.0.0. -->
<PackageVersion Include="JasperFx.RuntimeCompiler" Version="5.0.0" />
<PackageVersion Include="JasperFx.SourceGenerator" Version="2.8.2" />
<PackageVersion Include="JasperFx.SourceGenerator" Version="2.9.10" />
<PackageVersion Include="Marten" Version="9.6.0" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.1.3" />
<PackageVersion Include="Polecat" Version="4.2.1" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.46.1" />
<PackageVersion Include="Marten.AspNetCore" Version="9.6.0" />
<PackageVersion Include="Marten.Newtonsoft" Version="9.6.0" />
<PackageVersion Include="MemoryPack" Version="1.21.3" />
<PackageVersion Include="MessagePack" Version="3.1.3" />
<PackageVersion Include="MessagePack" Version="3.1.7" />
<PackageVersion Include="Meziantou.Extensions.Logging.Xunit" Version="1.0.15" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.14" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR" Version="1.2.9" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Wolverine;
using Wolverine.Attributes;
using Xunit;

namespace CoreTests.Acceptance;

// GH-3081: keyed services injected through a handler's CONSTRUCTOR were resolved by type only,
// dropping the [FromKeyedServices] key — so two keyed parameters of the same service type both
// resolved to the default (last) registration. Fixed in JasperFx 2.9.10: ConstructorFrame now
// resolves constructor parameters via the attribute-aware FindVariable(ParameterInfo) overload.
//
// Companion to using_with_keyed_services, which covers keyed services on Handle METHOD parameters
// (that path always worked because MethodCall already used the attribute-aware overload).
public class keyed_services_on_handler_constructor
{
[Fact]
public async Task each_keyed_constructor_parameter_resolves_to_its_own_registration()
{
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
opts.Discovery.DisableConventionalDiscovery().IncludeType<KeyedCtorHandler>();

opts.Services.AddKeyedScoped<IKeyedRepo, FirstRepo>("Test");
opts.Services.AddKeyedScoped<IKeyedRepo, SecondRepo>("Test2");
}).StartAsync();

KeyedCtorRecording.Seen.Clear();

await host.InvokeAsync(new KeyedCtorCommand());

// first ctor param -> "Test" -> FirstRepo; second -> "Test2" -> SecondRepo.
// Before the fix both parameters resolved to the last registration (SecondRepo).
KeyedCtorRecording.Seen.ShouldBe(["First", "Second"]);
}
}

public interface IKeyedRepo
{
string Name { get; }
}

public class FirstRepo : IKeyedRepo
{
public string Name => "First";
}

public class SecondRepo : IKeyedRepo
{
public string Name => "Second";
}

public static class KeyedCtorRecording
{
public static readonly List<string> Seen = new();
}

public record KeyedCtorCommand;

[WolverineIgnore]
public class KeyedCtorHandler(
[FromKeyedServices("Test")] IKeyedRepo first,
[FromKeyedServices("Test2")] IKeyedRepo second)
{
public void Handle(KeyedCtorCommand command)
{
KeyedCtorRecording.Seen.Add(first.Name);
KeyedCtorRecording.Seen.Add(second.Name);
}
}
Loading