Skip to content

Commit

Permalink
Added logic to support multiple container in .NET 8 DI
Browse files Browse the repository at this point in the history
Needed to modify basic Castle.Winsor library to support
the ability from IHandler interface to get the current kernel
associated with the handler. This is needed to find the correct
root scope associated with that kernel instance.
  • Loading branch information
alkampfergit committed Feb 18, 2024
1 parent 1830955 commit 7437a7c
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 165 deletions.
4 changes: 2 additions & 2 deletions buildscripts/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<NoWarn>$(NoWarn);CS1591;NU5048</NoWarn>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/castleproject/Windsor</RepositoryUrl>
<BuildVersion>6.0.0</BuildVersion>
<BuildVersion>0.0.0</BuildVersion>
<BuildVersion Condition="'$(APPVEYOR_BUILD_VERSION)'!=''">$(APPVEYOR_BUILD_VERSION)</BuildVersion>
<BuildVersionMajor>$(BuildVersion.Split('.')[0])</BuildVersionMajor>
<BuildVersionNoSuffix>$(BuildVersion.Split('-')[0])</BuildVersionNoSuffix>
Expand All @@ -18,7 +18,7 @@
<Product>Castle Windsor</Product>
<FileVersion>$(BuildVersionNoSuffix)</FileVersion>
<VersionPrefix>$(BuildVersion)</VersionPrefix>
<AssemblyVersion>6.0.0.0</AssemblyVersion>
<AssemblyVersion>$(BuildVersionMajor).0.0</AssemblyVersion>
<AssemblyTitle>Castle Windsor is best of breed, mature Inversion of Control container available for .NET</AssemblyTitle>
<Authors>Castle Project Contributors</Authors>
<PackageProjectUrl>http://www.castleproject.org/projects/windsor/</PackageProjectUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ protected override IServiceProvider BuildServiceProvider(IServiceCollection serv

public class CastleWindsorCustomAssumptionTests : CustomAssumptionTests
{
private WindsorServiceProviderFactory _factory;
private IWindsorContainer _container;

protected override IServiceCollection GetServiceCollection()
Expand All @@ -291,9 +292,9 @@ protected override IServiceCollection GetServiceCollection()

protected override IServiceProvider BuildServiceProvider(IServiceCollection serviceCollection)
{
var factory = new WindsorServiceProviderFactory();
_container = factory.CreateBuilder(serviceCollection);
return factory.CreateServiceProvider(_container);
_factory = new WindsorServiceProviderFactory();
_container = _factory.CreateBuilder(serviceCollection);
return _factory.CreateServiceProvider(_container);
}

[Fact]
Expand Down Expand Up @@ -351,6 +352,16 @@ public void TryToResolveScopedInOtherThread()

Assert.True(task.Result);
}


protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_factory.Dispose();
}
}
}

internal class TestService : ITestService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public ResolveFromThreadpoolUnsafe_NetStatic() : base(false)
/// NetStatic lifestyle.
/// </summary>
[Fact]
public async Task Cannot_Resolve_LifestyleNetStatic_From_WindsorContainer_NoRootScopeAvailable()
public async Task Can_Resolve_LifestyleNetStatic_From_WindsorContainer_NoRootScopeAvailable()
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -68,14 +68,13 @@ public async Task Cannot_Resolve_LifestyleNetStatic_From_WindsorContainer_NoRoot
{
var task = tcs.Task;
IUserService result = await task;
// The test succeeds if we use standard Castle Windsor Singleton lifestyle instead of the custom NetStatic lifestyle.
//with the fix we can now use correctly a fallback for the root scope so we can access root scope even
//if we are outside of scope
Assert.NotNull(result);
});

// This test will fail if we use NetStatic lifestyle
Assert.NotNull(ex);
Assert.IsType<InvalidOperationException>(ex);
Assert.Equal("No root scope available.", ex.Message);
Assert.Null(ex);

(sp as IDisposable)?.Dispose();
container.Dispose();
Expand Down Expand Up @@ -315,7 +314,7 @@ public async Task Cannot_Resolve_LifestyleScoped_From_ServiceProvider()
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -373,7 +372,7 @@ public async Task Cannot_Resolve_LifestyleScoped_From_WindsorContainer()
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -432,7 +431,7 @@ public async Task Can_Resolve_LifestyleScopedToNetServiceScope_From_ServiceProvi
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -475,7 +474,7 @@ public async Task Cannot_Resolve_LifestyleScopedToNetServiceScope_From_WindsorCo
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -540,7 +539,7 @@ public async Task Can_Resolve_LifestyleTransient_From_ServiceProvider()
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -583,7 +582,7 @@ public async Task Can_Resolve_LifestyleTransient_From_WindsorContainer()
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -631,7 +630,7 @@ public async Task Can_Resolve_LifestyleNetTransient_From_ServiceProvider_MemoryL
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down Expand Up @@ -674,7 +673,7 @@ public async Task Cannot_Resolve_LifestyleNetTransient_From_WindsorContainer_NoS
{
var serviceProvider = new ServiceCollection();
var container = new WindsorContainer();
var f = new WindsorServiceProviderFactory(container);
using var f = new WindsorServiceProviderFactory(container);
f.CreateBuilder(serviceProvider);

container.Register(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,119 +6,43 @@

namespace Castle.Windsor.Extensions.DependencyInjection.Tests
{
public class WindsorKeyedDependencyInjectionSpecificationTests : KeyedDependencyInjectionSpecificationTests
public class WindsorKeyedDependencyInjectionSpecificationTests : KeyedDependencyInjectionSpecificationTests, IDisposable
{
private bool _disposedValue;
private WindsorServiceProviderFactory _factory;

protected override IServiceProvider CreateServiceProvider(IServiceCollection collection)
{
if (collection is TestServiceCollection)
{
var factory = new WindsorServiceProviderFactory();
var container = factory.CreateBuilder(collection);
return factory.CreateServiceProvider(container);
_factory = new WindsorServiceProviderFactory();
var container = _factory.CreateBuilder(collection);
return _factory.CreateServiceProvider(container);
}

return collection.BuildServiceProvider();
}

//[Fact]
//public void ResolveKeyedServiceSingletonInstanceWithAnyKey2()
//{
// var serviceCollection = new ServiceCollection();
// serviceCollection.AddKeyedSingleton<IService, Service>(KeyedService.AnyKey);

// var provider = CreateServiceProvider(serviceCollection);

// Assert.Null(provider.GetService<IService>());

// var serviceKey1 = "some-key";
// var svc1 = provider.GetKeyedService<IService>(serviceKey1);
// Assert.NotNull(svc1);
// Assert.Equal(serviceKey1, svc1.ToString());

// var serviceKey2 = "some-other-key";
// var svc2 = provider.GetKeyedService<IService>(serviceKey2);
// Assert.NotNull(svc2);
// Assert.Equal(serviceKey2, svc2.ToString());
//}

internal interface IService { }

internal class Service : IService
{
private readonly string _id;

public Service() => _id = Guid.NewGuid().ToString();

public Service([ServiceKey] string id) => _id = id;

public override string? ToString() => _id;
}

internal class OtherService
protected virtual void Dispose(bool disposing)
{
public OtherService(
[FromKeyedServices("service1")] IService service1,
[FromKeyedServices("service2")] IService service2)
if (!_disposedValue)
{
Service1 = service1;
Service2 = service2;
}

public IService Service1 { get; }

public IService Service2 { get; }
}

public class FakeService : IFakeEveryService, IDisposable
{
public PocoClass Value { get; set; }

public bool Disposed { get; private set; }

public void Dispose()
{
if (Disposed)
if (disposing)
{
throw new ObjectDisposedException(nameof(FakeService));
_factory?.Dispose();
}

Disposed = true;
_disposedValue = true;
}
}

public interface IFakeEveryService :
IFakeService,
IFakeMultipleService,
IFakeScopedService
{
}

public interface IFakeMultipleService : IFakeService
{
}

public interface IFakeScopedService : IFakeService
{
}

public interface IFakeService
{
}

public class PocoClass
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}

//public class WindsorKeyedDependencyInjectionSpecificationExplicitContainerTests : KeyedDependencyInjectionSpecificationTests
//{
// protected override IServiceProvider CreateServiceProvider(IServiceCollection collection)
// {
// var factory = new WindsorServiceProviderFactory(new WindsorContainer());
// var container = factory.CreateBuilder(collection);
// return factory.CreateServiceProvider(container);
// }
//}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,36 @@ namespace Castle.Windsor.Extensions.DependencyInjection.Tests
using Microsoft.Extensions.DependencyInjection.Specification.Fakes;
using Xunit;

public class WindsorScopedServiceProviderCustomWindsorContainerTests : SkippableDependencyInjectionSpecificationTests
public class WindsorScopedServiceProviderCustomWindsorContainerTests : SkippableDependencyInjectionSpecificationTests, IDisposable
{
private bool _disposedValue;
private WindsorServiceProviderFactory _factory;

protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection)
{
var factory = new WindsorServiceProviderFactory(new WindsorContainer());
var container = factory.CreateBuilder(serviceCollection);
return factory.CreateServiceProvider(container);
_factory = new WindsorServiceProviderFactory(new WindsorContainer());
var container = _factory.CreateBuilder(serviceCollection);
return _factory.CreateServiceProvider(container);
}

protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_factory?.Dispose();
}

_disposedValue = true;
}
}

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}

#if NET6_0_OR_GREATER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,36 @@ namespace Castle.Windsor.Extensions.DependencyInjection.Tests
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Specification;

public class WindsorScopedServiceProviderTests : SkippableDependencyInjectionSpecificationTests
public class WindsorScopedServiceProviderTests : SkippableDependencyInjectionSpecificationTests, IDisposable
{
private bool _disposedValue;
private WindsorServiceProviderFactory _factory;

protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection)
{
var factory = new WindsorServiceProviderFactory();
var container = factory.CreateBuilder(serviceCollection);
return factory.CreateServiceProvider(container);
_factory = new WindsorServiceProviderFactory();
var container = _factory.CreateBuilder(serviceCollection);
return _factory.CreateServiceProvider(container);
}

protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_factory?.Dispose();
}

_disposedValue = true;
}
}

public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Castle.Windsor" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Castle.Windsor\Castle.Windsor.csproj" />
</ItemGroup>
</Project>
Loading

0 comments on commit 7437a7c

Please sign in to comment.