Skip to content

Commit

Permalink
Merge pull request #599 from seesharper/microsoft-compatibility
Browse files Browse the repository at this point in the history
Added compatibility with Microsoft.Extensions.DependencyInjection for keyed services.
  • Loading branch information
seesharper authored Nov 6, 2024
2 parents 6d3be2d + e85b228 commit 70eab3b
Show file tree
Hide file tree
Showing 24 changed files with 2,890 additions and 178 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ jobs:
uses: actions/setup-dotnet@v2.0.0
with:
dotnet-version: |
6.0.x
7.0.x
8.0.x
- name: Install dotnet-script
run: dotnet tool install --global dotnet-script
- name: Install dotnet-ilverify
Expand Down
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
"coverage-gutters.xmlname": "./CoverageResult/coverage.opencover.xml",
"omnisharp.path": "latest",
"cSpell.words": [
"APIKEY",
"BUILDENVIRONMENT",
"Callvirt",
"Castclass",
"Cloneable",
"Conv",
"decoratee",
"Initobj",
"Ldarg",
"Ldelem",
Expand All @@ -15,10 +19,12 @@
"Ldnull",
"Ldstr",
"MSIL",
"NETCOREAPP",
"Newarr",
"Newobj",
"Stelem",
"Stloc",
"Unkeyed",
"Xunit"
],
"dotnet-test-explorer.testArguments": "-c release -f netcoreapp2.0"
Expand Down
3 changes: 1 addition & 2 deletions build/build.csx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ using static ReleaseManagement;
[StepDescription("Runs the tests with test coverage")]
Step testcoverage = () =>
{
DotNet.TestWithCodeCoverage(Path.GetDirectoryName(BuildContext.TestProjects[0]), BuildContext.TestCoverageArtifactsFolder, BuildContext.CodeCoverageThreshold, "net7.0");
DotNet.TestWithCodeCoverage(Path.GetDirectoryName(BuildContext.TestProjects[0]), BuildContext.TestCoverageArtifactsFolder, BuildContext.CodeCoverageThreshold, "net8.0");
};

[StepDescription("Runs all the tests for all target frameworks")]
Step test = () =>
{
Test();
// DotNet.Test();
};

public static void Test()
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.100",
"version": "8.0.402",
"rollForward": "latestFeature"
}
}
1 change: 1 addition & 0 deletions packlocal.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dotnet pack "src/LightInject/LightInject.csproj" --configuration Release --output "build/Artifacts/NuGet" /property:Version=$1
15 changes: 15 additions & 0 deletions src/LightInject.Tests/ContainerMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -438,5 +438,20 @@ public object GetInstance(Type serviceType, Scope scope, string serviceName)
{
throw new NotImplementedException();
}

public IServiceRegistry RegisterOrdered(ServiceRegistration[] serviceRegistrations)
{
throw new NotImplementedException();
}

public IServiceRegistry Register<TService>(Func<IServiceFactory, string, TService> factory, string serviceName)
{
throw new NotImplementedException();
}

public IServiceRegistry Register<TService>(Func<IServiceFactory, string, TService> factory, string serviceName, ILifetime lifetime)
{
throw new NotImplementedException();
}
}
}
12 changes: 6 additions & 6 deletions src/LightInject.Tests/DecoratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ public void GetInstance_LazyDecoratorFollowedByNonLazyDecorator_ReturnsDecorated


[Fact]
public void GetInstance_SingletonInjectecIntoTwoDifferentClasses_DoesNotReapplyDecorators()
public void GetInstance_SingletonInjectedIntoTwoDifferentClasses_DoesNotReapplyDecorators()
{
BarDecorator.Instances = 0;
var container = CreateContainer();
Expand All @@ -366,7 +366,7 @@ public void GetInstance_SingletonInjectecIntoTwoDifferentClasses_DoesNotReapplyD
}

[Fact]
public void GetAllInstances_SingletonInjectecIntoTwoDifferentClasses_DoesNotReapplyDecorators()
public void GetAllInstances_SingletonInjectedIntoTwoDifferentClasses_DoesNotReapplyDecorators()
{
BarDecorator.Instances = 0;
var container = CreateContainer();
Expand All @@ -381,7 +381,7 @@ public void GetAllInstances_SingletonInjectecIntoTwoDifferentClasses_DoesNotReap
}

[Fact]
public void GetInstance_PerScopeInjectecIntoTwoDifferentClasses_DoesNotReapplyDecorators()
public void GetInstance_PerScopeInjectedIntoTwoDifferentClasses_DoesNotReapplyDecorators()
{
BarDecorator.Instances = 0;
var container = CreateContainer();
Expand All @@ -399,7 +399,7 @@ public void GetInstance_PerScopeInjectecIntoTwoDifferentClasses_DoesNotReapplyDe
}

[Fact]
public void GetAllInstances_PerScopeInjectecIntoTwoDifferentClasses_DoesNotReapplyDecorators()
public void GetAllInstances_PerScopeInjectedIntoTwoDifferentClasses_DoesNotReapplyDecorators()
{
BarDecorator.Instances = 0;
var container = CreateContainer();
Expand Down Expand Up @@ -492,7 +492,7 @@ public void GetInstance_ClassWithConstructorArguments_ReturnsDecoratedInstance()
}

[Fact]
public void GetInstance_ClassWithConstructorArgumentsAndLazyDecorator_CanCrTCreeateTarget()
public void GetInstance_ClassWithConstructorArgumentsAndLazyDecorator_CanCreateTarget()
{
var container = CreateContainer();
container.Register<int, IFoo>((factory, i) => new FooWithValueTypeDependency(i));
Expand Down Expand Up @@ -599,7 +599,7 @@ public void GetInstance_DecoratorImplementingDisposableRegisteredAsSingleton_Dis
}

[Fact]
public void GetInstance_ServicaeAsFactoryAndDecoratorImplementingDisposableRegisteredAsSingleton_DisposesDecorator()
public void GetInstance_ServiceAsFactoryAndDecoratorImplementingDisposableRegisteredAsSingleton_DisposesDecorator()
{
var container = CreateContainer();
container.Register<IFoo>(sf => new DisposableFoo(), new PerContainerLifetime());
Expand Down
73 changes: 45 additions & 28 deletions src/LightInject.Tests/DisposableTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using LightInject.SampleLibrary;
using Xunit;
namespace LightInject.Tests
Expand Down Expand Up @@ -35,7 +37,7 @@ public void Dispose_ServiceWithPerRequestLifetime_IsDisposed()
}

[Fact]
public void Dispose_Singeltons_DisposesInReverseOrderOfCreation()
public void Dispose_Singletons_DisposesInReverseOrderOfCreation()
{
var container = CreateContainer();
container.Register<FakeDisposeCallback>(new PerContainerLifetime());
Expand All @@ -59,7 +61,7 @@ public void Dispose_Singeltons_DisposesInReverseOrderOfCreation()
}

[Fact]
public void Dispose_SingeltonWithFactory_DisposesInReverseOrderOfCreation()
public void Dispose_SingletonWithFactory_DisposesInReverseOrderOfCreation()
{
var container = CreateContainer();
container.Register<FakeDisposeCallback>(new PerContainerLifetime());
Expand Down Expand Up @@ -317,49 +319,64 @@ public FakeDisposableCallbackOuterService(IFakeService singleService, IEnumerabl
}
}

/// <summary>
/// An <see cref="ILifetime"/> implementation that makes it possible to mimic the notion of a root scope.
/// </summary>
[LifeSpan(30)]
internal class PerRootScopeLifetime : ILifetime, ICloneableLifeTime
{
private readonly ThreadSafeDictionary<Scope, object> instances = new ThreadSafeDictionary<Scope, object>();

private readonly object syncRoot = new object();
private readonly Scope rootScope;
private object instance;

/// <summary>
/// Initializes a new instance of the <see cref="PerRootScopeLifetime"/> class.
/// </summary>
/// <param name="rootScope">The root <see cref="Scope"/>.</param>
public PerRootScopeLifetime(Scope rootScope)
{
this.rootScope = rootScope;
}
=> this.rootScope = rootScope;

/// <inheritdoc/>
[ExcludeFromCodeCoverage]
public object GetInstance(Func<object> createInstance, Scope scope)
{
return instances.GetOrAdd(rootScope, s => CreateScopedInstance(s, createInstance));
}
=> throw new NotImplementedException("Uses optimized non closing method");

/// <inheritdoc/>
public ILifetime Clone()
=> new PerRootScopeLifetime(rootScope);

private void RegisterForDisposal(Scope scope, object instance)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable IDE0060
public object GetInstance(GetInstanceDelegate createInstance, Scope scope, object[] arguments)
{
if (instance is IDisposable disposable)
#pragma warning restore IDE0060
if (instance != null)
{
rootScope.TrackInstance(disposable);
return instance;
}
}

private object CreateScopedInstance(Scope scope, Func<object> createInstance)
{
rootScope.Completed += OnScopeCompleted;
var instance = createInstance();
lock (syncRoot)
{
if (instance == null)
{
instance = createInstance(arguments, rootScope);
RegisterForDisposal(instance);
}
}

RegisterForDisposal(rootScope, instance);
return instance;
}

private void OnScopeCompleted(object sender, EventArgs e)
{
var scope = (Scope)sender;
scope.Completed -= OnScopeCompleted;
instances.TryRemove(scope, out object removedInstance);
}

public ILifetime Clone()
private void RegisterForDisposal(object instance)
{
return new PerRootScopeLifetime(rootScope);
if (instance is IDisposable disposable)
{
rootScope.TrackInstance(disposable);
}
else if (instance is IAsyncDisposable asyncDisposable)
{
rootScope.TrackInstance(asyncDisposable);
}
}
}
}
14 changes: 11 additions & 3 deletions src/LightInject.Tests/EmitterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace LightInject.Tests
using System;
using System.Reflection;
using System.Reflection.Emit;

using LightInject.SampleLibrary;
using Xunit;


Expand Down Expand Up @@ -103,7 +103,7 @@ public void Push_Seven_EmitsMostEffectiveInstruction()
}

[Fact]
public void Push_Eigth_EmitsMostEffectiveInstruction()
public void Push_Eighth_EmitsMostEffectiveInstruction()
{
var emitter = CreateEmitter();

Expand Down Expand Up @@ -652,7 +652,7 @@ public void Emit_InvalidOpCodeForString_ThrowsException()
{
var emitter = new Emitter(null, new Type[] { });

Assert.Throws<NotSupportedException>(() => emitter.Emit(OpCodes.Call, "somestring"));
Assert.Throws<NotSupportedException>(() => emitter.Emit(OpCodes.Call, "SomeString"));
}

[Fact]
Expand All @@ -679,6 +679,14 @@ public void ToString_InstructionOfT_ReturnsCodeAndArgumentAsString()
Assert.Equal("ldarg 1", instruction.ToString(), StringComparer.OrdinalIgnoreCase);
}

[Fact]
public void EmitMethodInfoShouldHaveServiceType()
{
var emitMethodInfo = new EmitMethodInfo(typeof(IFoo), (e) => { }, 0, false);
Assert.Equal(typeof(IFoo), emitMethodInfo.ServiceType);

}

#if !USE_EXPRESSIONS
private ILGenerator CreateDummyGenerator(Type[] parameterTypes)
{
Expand Down
16 changes: 16 additions & 0 deletions src/LightInject.Tests/EnumerableTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Collections.Generic;
using LightInject.SampleLibrary;
using Xunit;

namespace LightInject.Tests;

public class EnumerableTests
{
[Fact]
public void Method()
{
var container = new ServiceContainer();
container.RegisterSingleton<IEnumerable<IFoo>>(f => new IFoo[] { new Foo(), new AnotherFoo() });
var test = container.GetAllInstances<IFoo>();
}
}
Loading

0 comments on commit 70eab3b

Please sign in to comment.