Skip to content

Commit

Permalink
Updated nuget test adapter fixed a resolution bug
Browse files Browse the repository at this point in the history
The bug happened when you register a service with one NON keyed
component then again with KEYED components. The adapter incorrectly
checked only the first returned service for KEYED and returns null.

Identified after update to Orleans 8.1.0
  • Loading branch information
alkampfergit committed May 21, 2024
1 parent 36bbbf1 commit 8529c4f
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="11.0.0" />
<PackageReference Include="Microsoft.Web.Infrastructure" Version="1.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="11.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi" Version="5.2.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="11.0.0" />
<PackageReference Include="Microsoft.Web.Infrastructure" Version="1.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<ItemGroup>
<!-- This is an intentional upgrade to NUnit. This is the solution for https://github.com/castleproject/Windsor/issues/243 once we upgrade NUnit and make dotnet test a first class citizen-->
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.0.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.assert" Version="2.4.2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#if NET8_0_OR_GREATER
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Specification.Fakes;
using System;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -110,6 +109,21 @@ public void Scoped_service_resolved_outside_scope()
Assert.Equal(resolvedOutsideScope, resolvedAgainOutsideScope);
}

[Fact]
public void Mix_of_keyed_and_not_keyed()
{
var serviceCollection = GetServiceCollection();
serviceCollection.AddSingleton<ITestService, TestService>();
serviceCollection.AddKeyedSingleton<ITestService, AnotherTestService>("bla");

_serviceProvider = BuildServiceProvider(serviceCollection);

//can resolve the non-keyed
var nonKeyed = _serviceProvider.GetRequiredService<ITestService>();
Assert.NotNull(nonKeyed);
Assert.IsType<TestService>(nonKeyed);
}

[Fact]
public void Scoped_service_resolved_outside_scope_in_another_thread()
{
Expand Down Expand Up @@ -167,7 +181,8 @@ public async void Simulate_async_timer_without_wait()
ITestService resolvedInThread = null;
async Task ExecuteAsync()
{
while (!stop)
DateTime start = DateTime.UtcNow;
while (!stop && DateTime.UtcNow.Subtract(start).TotalSeconds < 10)
{
await Task.Delay(100);
if (shouldResolve)
Expand All @@ -178,10 +193,7 @@ async Task ExecuteAsync()
}
}
//fire and forget
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
var task = ExecuteAsync();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

await Task.Delay(500);

var serviceCollection = GetServiceCollection();
Expand Down Expand Up @@ -353,7 +365,6 @@ public void TryToResolveScopedInOtherThread()
Assert.True(task.Result);
}


protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Expand All @@ -364,16 +375,10 @@ protected override void Dispose(bool disposing)
}
}

internal class TestService : ITestService
{
}
internal class TestService : ITestService;

internal class AnotherTestService : ITestService
{
}
internal class AnotherTestService : ITestService;

internal interface ITestService
{
}
internal interface ITestService;
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

namespace Castle.Windsor.Extensions.DependencyInjection
{
using Castle.MicroKernel;
using Castle.MicroKernel.Handlers;
using Castle.Windsor;
using Castle.Windsor.Extensions.DependencyInjection.Scope;
Expand Down Expand Up @@ -99,15 +100,26 @@ private object ResolveInstanceOrNull(Type serviceType, bool isOptional)
//this is complicated by the concept of keyed service, because if you are about to resolve WITHOUTH KEY you do not
//need to resolve keyed services. Now Keyed services are available only in version 8 but we register with an helper
//all registered services so we can know if a service was really registered with keyed service or not.
var componentRegistration = container.Kernel.GetHandler(serviceType);
if (componentRegistration.ComponentModel.Name.StartsWith(KeyedRegistrationHelper.KeyedRegistrationPrefix))
var componentRegistrations = container.Kernel.GetHandlers(serviceType);

//now since the caller requested a NON Keyed component, we need to skip all keyed components.
var realRegistrations = componentRegistrations.Where(x => !x.ComponentModel.Name.StartsWith(KeyedRegistrationHelper.KeyedRegistrationPrefix)).ToList();
if (realRegistrations.Count == 0)
{
//Component was registered as keyed component, so we really need to resolve with null because this is the old interface
//so no key is provided.
//No component is registered for the interface without key, resolution cannot be done.
return null;
}
#endif
else if (realRegistrations.Count > 1)
{
//more than one component is registered for the interface without key, resolution cannot be done.
throw new ComponentResolutionException($"More than one component is registered for the interface {serviceType.FullName} without key, resolution cannot be done.");
}

return container.Resolve(realRegistrations[0].ComponentModel.Name, serviceType);
#else
//no keyed component, just resolve.
return container.Resolve(serviceType);
#endif
}

if (serviceType.GetTypeInfo().IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
Expand Down
2 changes: 1 addition & 1 deletion src/Castle.Windsor.Tests/Castle.Windsor.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<PackageReference Include="Castle.Core-log4net" Version="[5.1.0,6.0)" />
<PackageReference Include="Castle.Core-NLog" Version="[5.1.0,6.0)" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='net462'">
Expand Down

0 comments on commit 8529c4f

Please sign in to comment.