Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Castle.Windsor.Extensions.DependencyInjection: support parallel containers (see #563) #577

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d0b3975
Encapsulate single root scope in WindsorScopeFactory
rvdginste Nov 30, 2020
d46be5b
Add test with external container
generik0 Dec 2, 2020
9d8a864
Merge remote-tracking branch 'castle.windsor/master' into feature/sup…
generik0 Dec 7, 2020
d3aecbf
Change BeginScope to utilize the self contained current scope
generik0 Dec 7, 2020
558d545
Improve readability of null handling for scopes
generik0 Dec 7, 2020
07ff3e3
Cleanup
generik0 Dec 8, 2020
1e1f6ef
Remove unneded field rootScope in favour of private set property
generik0 Dec 9, 2020
6d8fb32
Clean up modifiers and code
generik0 Dec 9, 2020
f7d06b5
Move scope classes to scop folder
generik0 Dec 9, 2020
6192d33
Fix namespaces for moved scope classes
generik0 Dec 9, 2020
ba6a8cb
Move ForcedScope no longer to be an inner class for ExtensionContaine…
generik0 Dec 9, 2020
00ccc0e
Change Current property to handle nulls with exceptiion. Current must…
generik0 Dec 9, 2020
af05190
Remove var, only keep discard
generik0 Dec 9, 2020
4df5c19
Cleanup
generik0 Dec 9, 2020
c12a810
Remove unneded passing of RootScope as it is in the parent.
generik0 Dec 9, 2020
ecfa403
Rename CurrentOrThrow to Current
generik0 Dec 10, 2020
36ac910
Add check that the disposing scope is current, before changing the pa…
generik0 Dec 10, 2020
3a3a63e
Move the set of the curr3ent.Value to the ctor from the ExtensionCont…
generik0 Dec 10, 2020
bdf3507
Merge remote-tracking branch 'castle.windsor/master' into feature/sup…
generik0 Dec 10, 2020
32ce9c5
Improve ordering for readability
generik0 Dec 10, 2020
f6740c4
Rename ExtensionContainerScope to Base
generik0 Dec 10, 2020
414887d
Make ExtensionContainerRootScope and ExtensionContainerRoot use a base
generik0 Dec 10, 2020
e039c17
Change BeginScope and BeginRootScope to set current
generik0 Dec 10, 2020
5c7f535
Move Current into its own static class
generik0 Dec 10, 2020
6d4d75e
Cleanup
generik0 Dec 10, 2020
b9753fb
Cleanup
generik0 Dec 10, 2020
34b0d9f
Fix TransientMarker to be readonly
generik0 Dec 15, 2020
0c04c83
Remove unneeded exception when the getter already throws
generik0 Dec 15, 2020
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
@@ -0,0 +1,31 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.DependencyInjection.Tests
{
using System;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Specification;

public class WindsorScopedServiceProviderCustomWindsorContainerTests : DependencyInjectionSpecificationTests
{
protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var factory = new WindsorServiceProviderFactory(new WindsorContainer());
var container = factory.CreateBuilder(serviceCollection);
return factory.CreateServiceProvider(container);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ namespace Castle.Windsor.Extensions.DependencyInjection.Scope
{
internal class ExtensionContainerRootScope : ExtensionContainerScope
{
internal static ExtensionContainerRootScope RootScope {get; private set;}
private ExtensionContainerRootScope() : base(null)
private ExtensionContainerRootScope() : base(null, null)
{

}

public static ExtensionContainerRootScope BeginRootScope()
{
var scope = new ExtensionContainerRootScope();
ExtensionContainerScope.current.Value = scope;
RootScope = scope;
current.Value = scope;
return scope;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,29 @@
namespace Castle.Windsor.Extensions.DependencyInjection.Scope
{
using System;

using Castle.MicroKernel.Context;
using Castle.MicroKernel.Lifestyle.Scoped;

internal class ExtensionContainerRootScopeAccessor : IScopeAccessor
{
public ILifetimeScope GetScope(CreationContext context)
{
if (ExtensionContainerRootScope.RootScope == null)
if (ExtensionContainerScope.Current == null)
{
throw new InvalidOperationException("No root scope");
}

if (ExtensionContainerScope.Current.RootScope == null)
{
throw new InvalidOperationException("No root scope");
}

return ExtensionContainerRootScope.RootScope;
return ExtensionContainerScope.Current.RootScope;
}
jonorossi marked this conversation as resolved.
Show resolved Hide resolved

public void Dispose()
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,38 @@ namespace Castle.Windsor.Extensions.DependencyInjection.Scope
using Castle.Core;
using Castle.MicroKernel;
using Castle.MicroKernel.Lifestyle.Scoped;

internal class ExtensionContainerScope : ILifetimeScope, IDisposable
{
public static ExtensionContainerScope Current => current.Value;
public static string TransientMarker = "Transient";
protected static readonly AsyncLocal<ExtensionContainerScope> current = new AsyncLocal<ExtensionContainerScope>();
private readonly ExtensionContainerScope parent;
private readonly ExtensionContainerRootScope rootScope;
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
private readonly IScopeCache scopeCache;

protected ExtensionContainerScope(ExtensionContainerScope parent)
protected ExtensionContainerScope(
ExtensionContainerScope parent,
ExtensionContainerRootScope rootScope)
{
scopeCache = new ScopeCache();
if(parent == null)
{
this.parent = ExtensionContainerRootScope.RootScope;
}
else
{
this.parent = parent;
}
this.parent = parent ?? rootScope;
this.rootScope = rootScope;
}

public static ExtensionContainerScope BeginScope(ExtensionContainerScope parent)
public ExtensionContainerRootScope RootScope
=> this as ExtensionContainerRootScope ?? rootScope;

public static ExtensionContainerScope BeginScope(ExtensionContainerScope parent, ExtensionContainerRootScope rootScope)
{
var scope = new ExtensionContainerScope(parent);
if (rootScope == null)
throw new ArgumentNullException(nameof(rootScope));
jonorossi marked this conversation as resolved.
Show resolved Hide resolved

var scope = new ExtensionContainerScope(parent, rootScope);
current.Value = scope;
return scope;
}


public void Dispose()
{
var disposableCache = scopeCache as IDisposable;
Expand All @@ -65,7 +67,6 @@ public Burden GetCachedInstance(ComponentModel model, ScopedInstanceActivationCa
{
lock (scopeCache)
{

// Add transient's burden to scope so it gets released
if (model.Configuration.Attributes.Get(TransientMarker) == bool.TrueString)
{
Expand Down Expand Up @@ -102,4 +103,4 @@ public void Dispose()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,37 @@
namespace Castle.Windsor.Extensions.DependencyInjection
{
using System;

using Castle.Windsor;
using Castle.Windsor.Extensions.DependencyInjection.Scope;

using Microsoft.Extensions.DependencyInjection;

internal class WindsorScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer scopeFactoryContainer;
private readonly ExtensionContainerRootScope rootScope;
jonorossi marked this conversation as resolved.
Show resolved Hide resolved

public WindsorScopeFactory(IWindsorContainer container)
public WindsorScopeFactory(
IWindsorContainer container,
ExtensionContainerRootScope rootScope)
{
scopeFactoryContainer = container;
this.rootScope = rootScope;
}

public IServiceScope CreateScope()
{
var scope = ExtensionContainerScope.BeginScope(ExtensionContainerScope.Current);

var scope =
ExtensionContainerScope
.BeginScope(
ExtensionContainerScope.Current,
rootScope);
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
jonorossi marked this conversation as resolved.
Show resolved Hide resolved

//since WindsorServiceProvider is scoped, this gives us new instance
var provider = scopeFactoryContainer.Resolve<IServiceProvider>();

return new ServiceScope(scope, provider);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ public sealed class WindsorServiceProviderFactory : WindsorServiceProviderFactor

public WindsorServiceProviderFactory()
{
CreateRootContainer();
CreateRootScope();
CreateRootContainer();
}

public WindsorServiceProviderFactory(IWindsorContainer container)
{
SetRootContainer(container);
CreateRootScope();
SetRootContainer(container);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected virtual void CreateRootScope()
{
rootScope = ExtensionContainerRootScope.BeginRootScope();
}

protected virtual void CreateRootContainer()
{
SetRootContainer(new WindsorContainer());
Expand Down Expand Up @@ -82,7 +82,7 @@ protected virtual IWindsorContainer BuildContainer(IServiceCollection serviceCol
RegisterContainer(rootContainer);
RegisterProviders(rootContainer);
RegisterFactories(rootContainer);

AddSubResolvers();

RegisterServiceCollection(serviceCollection, windsorContainer);
Expand Down Expand Up @@ -111,6 +111,7 @@ protected virtual void RegisterFactories(IWindsorContainer container)
container.Register(Component
.For<IServiceScopeFactory>()
.ImplementedBy<WindsorScopeFactory>()
.DependsOn(Dependency.OnValue<ExtensionContainerRootScope>(rootScope))
.LifestyleSingleton(),
Component
.For<IServiceProviderFactory<IWindsorContainer>>()
Expand All @@ -133,4 +134,4 @@ protected virtual void AddSubResolvers()
rootContainer.Kernel.Resolver.AddSubResolver(new LoggerDependencyResolver(rootContainer.Kernel));
}
}
}
}