Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6ed4084
initial implementation of optional keyed services
DominicUllmann Dec 24, 2025
439a94a
add support for keyed required service
DominicUllmann Dec 24, 2025
dd9919e
add test for keyedimplementationfactory as well
DominicUllmann Dec 24, 2025
f30ada7
refactor to remove code duplication in ServiceCollectionAdapter
DominicUllmann Dec 24, 2025
6521615
ensure that transient factory works as well correct with keyed service
DominicUllmann Dec 24, 2025
e9fadc6
align with ienumerable resolution in the Microsoft DI world
DominicUllmann Dec 24, 2025
85902e7
simplify code
DominicUllmann Dec 24, 2025
20ceda7
Added the keyed service specification tests to the compliance test pr…
lord-executor Dec 26, 2025
b03a743
start to fix compliance tests
DominicUllmann Dec 26, 2025
5919021
add initial support for KeyedService.AnyKey
DominicUllmann Dec 26, 2025
a11c483
remove check for no contraint. We have always a constraint now with e…
DominicUllmann Dec 26, 2025
09ef1f9
add support for ServiceKeyAttribute and FromKeyedService
DominicUllmann Dec 28, 2025
baf79ef
remove SelfBIndingResolver as one tests check that no automatic self …
DominicUllmann Dec 28, 2025
13f268b
fix binding overriding with keyed services
DominicUllmann Dec 28, 2025
61c9c5a
handle special cases with AnyKey as well as with null key
DominicUllmann Dec 28, 2025
cb44ae5
ensure that we only match non-keyed if ServiceLookupMode is NullKey
DominicUllmann Dec 28, 2025
e6fe5d0
introduce runtime parameter so that we can inject the servicekey used…
DominicUllmann Dec 28, 2025
32d066f
fix open generics resolution
DominicUllmann Dec 28, 2025
ae84882
fix exception when trying unsupported case for servicekey
DominicUllmann Dec 28, 2025
87ea24c
refactor to support dynamic binding of services registred with anykey…
DominicUllmann Dec 30, 2025
fd04c75
add support for inheriting fromkeyedservices value for the constraint…
DominicUllmann Dec 31, 2025
4abe129
throw InvalidOperationException in case a required service or a fromk…
DominicUllmann Dec 31, 2025
2a5ef58
support default parameter values
DominicUllmann Dec 31, 2025
8e0802e
ignore tests which are not reasonable for a NInject based implementation
DominicUllmann Dec 31, 2025
3e6dfa9
simplify code, fix review
DominicUllmann Dec 31, 2025
e7f7c05
fix comments
DominicUllmann Dec 31, 2025
6bb6ccb
improve binding and comment
DominicUllmann Jan 2, 2026
299b11f
use a class instead of just a string constant for unkeyed index key
DominicUllmann Jan 2, 2026
baa6471
remove no longer needed code
DominicUllmann Jan 2, 2026
a99aa77
rename metadata
DominicUllmann Jan 2, 2026
765aaf3
add also FromKeyedServices which has a FromKeyServicesChild as well
DominicUllmann Jan 2, 2026
d605d0c
add same performance improvement as Ninject does for reading constraints
DominicUllmann Jan 2, 2026
20ef1d1
replace resolve of GetCustomAttributes but redirect to new lazy field
DominicUllmann Jan 2, 2026
f310f0a
correct way to restore wanring
DominicUllmann Jan 2, 2026
6d5c284
remove another warning
DominicUllmann Jan 2, 2026
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
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
using Microsoft.Extensions.DependencyInjection;
using System;

namespace Ninject.Web.AspNetCore.ComplianceTests
namespace Ninject.Web.AspNetCore.ComplianceTest;

/// <summary>
/// See https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src - the dotnet/runtime
/// project which contains the dependency injection library code also contains a set of "compliance tests" that can be run against a potential alternative
/// implementation to check if it is compliant. This class here is doing just that.
///
/// The project also contains a separate test project that includes these compliance tests for a set of compliant third party DI implementations like
/// Autofac and Lightinject under https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests.
///
/// All of this is part of the https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln
/// solution of dotnet/runtime.
/// </summary>
public class DependencyInjectionComplianceTests : Microsoft.Extensions.DependencyInjection.Specification.DependencyInjectionSpecificationTests
{
/// <summary>
/// See https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src - the dotnet/runtime
/// project which contains the dependency injection library code also contains a set of "compliance tests" that can be run against a potential alternative
/// implementation to check if it is compliant. This class here is doing just that.
///
/// The project also contains a separate test project that includes these compliance tests for a set of compliant third party DI implementations like
/// Autofac and Lightinject under https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests.
///
/// All of this is part of the https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln
/// solution of dotnet/runtime.
/// </summary>
public class DependencyInjectionComplianceTests : Microsoft.Extensions.DependencyInjection.Specification.DependencyInjectionSpecificationTests
protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var kernel = new AspNetCoreKernel();
var factory = new NinjectServiceProviderFactory(kernel);
var kernel = new AspNetCoreKernel();
var factory = new NinjectServiceProviderFactory(kernel);

return factory.CreateBuilder(serviceCollection).Build();
}
return factory.CreateBuilder(serviceCollection).Build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Ninject.Planning.Bindings.Resolvers;
using Xunit;

namespace Ninject.Web.AspNetCore.ComplianceTest;

/// <summary>
/// See https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src - the dotnet/runtime
/// project which contains the dependency injection library code also contains a set of "compliance tests" that can be run against a potential alternative
/// implementation to check if it is compliant. This class is running the dedicated specification tests for KEYED services.
/// </summary>
public class KeyedDependencyInjectionComplianceTests : Microsoft.Extensions.DependencyInjection.Specification.KeyedDependencyInjectionSpecificationTests
{
protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var kernel = new AspNetCoreKernel();
// remove autobinding as CreateServiceWithKeyedParameter e.g. tests that no autobinding happens.
kernel.Components.Remove<IMissingBindingResolver, SelfBindingResolver>();
var factory = new NinjectServiceProviderFactory(kernel);

return factory.CreateBuilder(serviceCollection).Build();
}

#pragma warning disable xUnit1024, xUnit1026

[Theory(Skip = "Wrong implementation of the test, should use Assert.Equal and not Assert.Same")]
[InlineData(true)]
[InlineData(false)]
public new void ResolveWithAnyKeyQuery_Constructor(bool anyKeyQueryBeforeSingletonQueries)
{
}

[Theory(Skip = "Wrong implementation, should use Assert.Equal and not Assert.Same")]
[InlineData(true)]
[InlineData(false)]
public new void ResolveWithAnyKeyQuery_Constructor_Duplicates(bool anyKeyQueryBeforeSingletonQueries)
{
}
#pragma warning restore xUnit1024, xUnit1026
}
9 changes: 9 additions & 0 deletions src/Ninject.Web.AspNetCore.Test/Fakes/IKeyedWeaponStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Ninject.Web.AspNetCore.Test.Fakes
{
#if NET8_0_OR_GREATER
public interface IKeyedWeaponStorage
{
IWeapon Weapon { get; }
}
#endif
}
18 changes: 18 additions & 0 deletions src/Ninject.Web.AspNetCore.Test/Fakes/KeyedNinja.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;

namespace Ninject.Web.AspNetCore.Test.Fakes
{
#if NET8_0_OR_GREATER
public class KeyedNinja : IWarrior
{
public object Key {get; private set;}

public KeyedNinja([ServiceKey] object key)
{
Key = key;
}

public string Name => nameof(KeyedNinja);
}
#endif
}
15 changes: 15 additions & 0 deletions src/Ninject.Web.AspNetCore.Test/Fakes/KeyedWeaponStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Extensions.DependencyInjection;

namespace Ninject.Web.AspNetCore.Test.Fakes
{
#if NET8_0_OR_GREATER
public class KeyedWeaponStorage : IKeyedWeaponStorage
{
public IWeapon Weapon { get; private set; }
public KeyedWeaponStorage([FromKeyedServices("Lance")] IWeapon lance)
{
Weapon = lance;
}
}
#endif
}
22 changes: 22 additions & 0 deletions src/Ninject.Web.AspNetCore.Test/Fakes/NinjaWithKeyedWeapon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;

namespace Ninject.Web.AspNetCore.Test.Fakes
{
#if NET8_0_OR_GREATER

public class NinjaWithKeyedWeapon : IWarrior
{
public IKeyedWeaponStorage Storage { get; private set; }
public IWeapon Weapon { get; private set; }

public string Name => nameof(NinjaWithKeyedWeapon) + $" with weapon {Weapon.Type}";

public NinjaWithKeyedWeapon([FromKeyedServices("Longsword")] IWeapon weapon, [FromKeyedServices("Storage")] IKeyedWeaponStorage storage)
{
Weapon = weapon;
Storage = storage;
}
}

#endif
}
20 changes: 18 additions & 2 deletions src/Ninject.Web.AspNetCore.Test/Unit/DuplicateDescriptorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,15 @@ public void BindingsFromKernel_ResolveWarrior_FailsWithActivationException(Resol
else
{
Action action = () => resolver.Resolve<IWarrior>(kernel);
action.Should().Throw<ActivationException>().WithMessage("Error activating IWarrior*");
if (resolver.ResolveType == ResolveType.ServiceProviderRequired)
{
action.Should().Throw<InvalidOperationException>().WithInnerException<ActivationException>()
.WithMessage("Error activating IWarrior*");
}
else
{
action.Should().Throw<ActivationException>().WithMessage("Error activating IWarrior*");
}
}
}

Expand Down Expand Up @@ -99,7 +107,15 @@ public void BindingsMixedWarriorDescriptors_ResolveWarrior_FailsWithActivationEx
else
{
Action action = () => resolver.Resolve<IWarrior>(kernel);
action.Should().Throw<ActivationException>().WithMessage("Error activating IWeapon*");
if (resolver.ResolveType == ResolveType.ServiceProviderRequired)
{
action.Should().Throw<InvalidOperationException>().WithInnerException<ActivationException>()
.WithMessage("Error activating IWeapon*");
}
else
{
action.Should().Throw<ActivationException>().WithMessage("Error activating IWeapon*");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public DummyBinding()

public DummyBinding WithIndex(BindingIndex index)
{
Metadata.Set(nameof(BindingIndex), index.Next(Service));
Metadata.Set(nameof(BindingIndex), index.Next(Service, BindingIndex.UnkeyedIndexKey.Instance));
return this;
}

Expand Down
Loading
Loading