Skip to content

Commit

Permalink
Merge branch 'feature-880' of https://github.com/simpleinjector/Simpl…
Browse files Browse the repository at this point in the history
…eInjector into v5.3.x
  • Loading branch information
dotnetjunkie committed Jan 7, 2021
2 parents 11e9d99 + 73f3414 commit e49bbdd
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,22 @@ public void Dispose_ObjectRegisteredForDisposalUsingRequestedCurrentLifetimeScop
Assert.IsTrue(instanceToDispose.HasBeenDisposed);
}

[TestMethod]
public void GetCurrentScope_WithCurrentScopeSet_ReturnsTheSetScope()
{
var lifestyle = new AsyncScopedLifestyle();
var container = new Container();
var expectedScope = new Scope(container);

// Act
lifestyle.SetCurrentScope(expectedScope);

// Assert
var actualScope = lifestyle.GetCurrentScope(container);

Assert.AreSame(expectedScope, actualScope);
}

private static async Task Inner(Container container, ICommand command)
{
DisposableCommand cmd1, cmd2;
Expand Down
4 changes: 4 additions & 0 deletions src/SimpleInjector/Lifestyles/AsyncScopedLifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public static Scope BeginScope(Container container)
/// <returns>A <see cref="Scope"/> instance or null when there is no scope active in this context.</returns>
protected override Scope? GetCurrentScopeCore(Container container) =>
GetScopeManager(container).CurrentScope;

/// <inheritdoc />
protected override void SetCurrentScopeCore(Scope scope) =>
GetScopeManager(scope.Container!).SetCurrentScope(scope);

private static ScopeManager GetScopeManager(Container c) => c.ContainerScope.GetOrSetItem(managerKey, CreateManager);

Expand Down
3 changes: 3 additions & 0 deletions src/SimpleInjector/Lifestyles/FlowingScopedLifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ public FlowingScopedLifestyle() : base("Scoped")

protected override Scope? GetCurrentScopeCore(Container container) =>
container.GetVerificationOrResolveScopeForCurrentThread();

protected override void SetCurrentScopeCore(Scope scope) =>
scope.Container!.CurrentThreadResolveScope = scope;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ internal override int DependencyLength(Container container) =>
protected override Scope? GetCurrentScopeCore(Container container) =>
this.CurrentLifestyle(container).GetCurrentScope(container);

protected override void SetCurrentScopeCore(Scope scope) =>
this.CurrentLifestyle(scope.Container!).SetCurrentScope(scope);

private ScopedLifestyle CurrentLifestyle(Container container) =>
this.selector(container) ? this.trueLifestyle : this.falseLifestyle;

Expand Down
2 changes: 2 additions & 0 deletions src/SimpleInjector/Lifestyles/ScopeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ private Scope? CurrentScopeInternal
set { this.scopeReplacer(value); }
}

internal void SetCurrentScope(Scope scope) => this.CurrentScopeInternal = scope;

internal Scope BeginScope() =>
this.CurrentScopeInternal = new Scope(this.container, this, this.GetCurrentScopeWithAutoCleanup());

Expand Down
5 changes: 5 additions & 0 deletions src/SimpleInjector/Lifestyles/ScopedProxyLifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace SimpleInjector.Lifestyles
{
using System;

// This lifestyle is exposed by the Lifestyle.Scoped property and forwards any calls to the lifestyle
// configured in Container.Options.DefaultScopedLifestyle.
internal sealed class ScopedProxyLifestyle : ScopedLifestyle
{
public ScopedProxyLifestyle() : base("Scoped")
Expand All @@ -30,6 +32,9 @@ protected internal override Registration CreateRegistrationCore<TService>(
protected override Scope? GetCurrentScopeCore(Container container) =>
GetDefaultScopedLifestyle(container).GetCurrentScope(container);

protected override void SetCurrentScopeCore(Scope scope) =>
GetDefaultScopedLifestyle(scope.Container!).SetCurrentScope(scope);

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static ScopedLifestyle GetDefaultScopedLifestyle(Container container) =>
container.Options.DefaultScopedLifestyle ?? ThrowDefaultScopeLifestyleIsNotSet();
Expand Down
4 changes: 4 additions & 0 deletions src/SimpleInjector/Lifestyles/ThreadScopedLifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public static Scope BeginScope(Container container)
protected override Scope? GetCurrentScopeCore(Container container) =>
GetScopeManager(container).CurrentScope;

/// <inheritdoc />
protected override void SetCurrentScopeCore(Scope scope) =>
GetScopeManager(scope.Container!).SetCurrentScope(scope);

private static ScopeManager GetScopeManager(Container container) =>
container.ContainerScope.GetOrSetItem(ManagerKey, CreateManager);

Expand Down
40 changes: 40 additions & 0 deletions src/SimpleInjector/ScopedLifestyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@ public void RegisterForDisposal(Container container, IDisposable disposable)
return this.GetCurrentScopeInternal(container);
}

/// <summary>
/// Sets the given <paramref name="scope"/> as current scope in the given context.
/// </summary>
/// <param name="scope">The current scope.</param>
/// <exception cref="NullReferenceException">Thrown when <paramref name="scope"/> is a null reference.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="scope"/> is not related to
/// a <see cref="Container"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when there is already an active scope in the
/// current context.</exception>
/// <exception cref="NotSupportedException">Thrown when the implementation does not support setting
/// the current scope.</exception>
public void SetCurrentScope(Scope scope)
{
Requires.IsNotNull(scope, nameof(scope));

if (scope.Container is null)
{
throw new ArgumentException("The scope has no related Container.", nameof(scope));
}

if (this.GetCurrentScope(scope.Container) != null)
{
throw new InvalidOperationException(
$"This method can only be called in case {nameof(GetCurrentScope)} returns null.");
}

this.SetCurrentScopeCore(scope);
}

/// <summary>
/// Creates a delegate that upon invocation return the current <see cref="Scope"/> for this
/// lifestyle and the given <paramref name="container"/>, or null when the delegate is executed outside
Expand Down Expand Up @@ -140,6 +169,17 @@ protected internal override Registration CreateRegistrationCore(Type concreteTyp
return currentScopeProvider.Invoke();
}

/// <summary>
/// Sets the given <paramref name="scope"/> as current scope in the given context.
/// </summary>
/// <param name="scope">The scope instance to set.</param>
protected virtual void SetCurrentScopeCore(Scope scope)
{
throw new NotSupportedException(
$"Setting the current scope is not supported by the {this.Name} lifestyle " +
$"({this.GetType().ToFriendlyName()}.");
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private Scope GetCurrentScopeOrThrow(Container container)
{
Expand Down

0 comments on commit e49bbdd

Please sign in to comment.