Skip to content

Commit

Permalink
fixed: #378
Browse files Browse the repository at this point in the history
  • Loading branch information
maximv committed Feb 26, 2021
1 parent e42f5ea commit 0ef9d64
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 9 deletions.
7 changes: 4 additions & 3 deletions src/DryIoc/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,7 @@ Expression IContainer.GetDecoratorExpressionOrDefault(Request request)

// Define the list of ids for the already applied decorators
int[] appliedDecoratorIDs = null;
if (!decorators.IsNullOrEmpty())
if (!decorators.IsNullOrEmpty()) // todo: @perf check earlier for `p.DirectParent.IsEmpty && p.DirectParent.FactoryType != FactoryType.Service` to avoid method calling and check inside
{
appliedDecoratorIDs = GetAppliedDecoratorIDs(request);
if (!appliedDecoratorIDs.IsNullOrEmpty())
Expand Down Expand Up @@ -4817,9 +4817,10 @@ public static class ResolverContext
/// <summary>Returns root or self resolver based on request.</summary>
public static Expression GetRootOrSelfExpr(Request request) =>
request.Reuse is CurrentScopeReuse == false &&
request.DirectParent.IsSingletonOrDependencyOfSingleton &&
request.DirectParent.IsSingletonOrDependencyOfSingleton &&
!request.OpensResolutionScope &&
!request.IsDirectlyWrappedInFunc()
!request.IsDirectlyWrappedInFunc() &&
request.Rules.ThrowIfDependencyHasShorterReuseLifespan
? RootOrSelfExpr
: FactoryDelegateCompiler.ResolverContextParamExpr;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Text;
using DryIoc.MefAttributedModel;
using NUnit.Framework;

Expand All @@ -10,8 +8,8 @@ namespace DryIoc.IssuesTests
[TestFixture]
public class GHIssue378_InconsistentResolutionFailure
{
[Test, Ignore("Fails on DryIoc v4.7.3")]
public void Nested_scopes_undecorated_resolution_succeeds_but_decorated_resolution_fails()
[Test]
public void Nested_scopes_undecorated_resolution_succeeds_but_decorated_resolution_with_the_FactoryMethod_fails()
{
var c = new Container().WithMef()
.With(rules => rules
Expand All @@ -23,7 +21,7 @@ public void Nested_scopes_undecorated_resolution_succeeds_but_decorated_resoluti

// 2. IDecoratedService should be created via a factory method
var decoratorSetup = Setup.DecoratorWith(useDecorateeReuse: false);
var factoryMethod = new Func<Lazy<IDecoratedService>, IDecoratedService>(CreateDecoratedService).Method;
var factoryMethod = new Func<Lazy<IDecoratedService>, IDecoratedService>(DecorateService).Method;
c.Register(typeof(IDecoratedService), reuse: Reuse.Transient, made: Made.Of(factoryMethod), setup: decoratorSetup);

// global scope is opened once on application startup
Expand Down Expand Up @@ -51,13 +49,78 @@ public void Nested_scopes_undecorated_resolution_succeeds_but_decorated_resoluti
}
}

static IDecoratedService CreateDecoratedService(Lazy<IDecoratedService> lazy)
[Test]
public void Nested_scopes_undecorated_resolution_succeeds_but_decorated_resolution_with_the_RegisterDelegate_fails()
{
var c = new Container().WithMef()
.With(rules => rules
.WithoutThrowIfDependencyHasShorterReuseLifespan()
.WithDefaultReuse(Reuse.Scoped));

// 1. default registrations
c.RegisterExports(typeof(DecoratedService), typeof(DependencyService));

// 2. IDecoratedService should be created via a factory method
var decoratorSetup = Setup.DecoratorWith(useDecorateeReuse: false);
c.RegisterDelegate<Lazy<IDecoratedService>, IDecoratedService>(DecorateService, Reuse.Transient, decoratorSetup);

// global scope is opened once on application startup
using (var globalScope = c.OpenScope())
{
// request scopes are created for each request
using (var requestScope = globalScope.OpenScope())
{
Assert.DoesNotThrow(() =>
{
var decorated = requestScope.Resolve<IDecoratedService>();
decorated.Hello();
},
"Failed to use the decorated service!");
}
}
}

[Test]
public void Nested_scopes_decorated_resolution_should_throw_the_DependencyHasShorterReuseLifespan()
{
var c = new Container().WithMef()
.With(rules => rules
.WithDefaultReuse(Reuse.Scoped));

// 1. default registrations
c.RegisterExports(typeof(DecoratedService), typeof(DependencyService));

// 2. IDecoratedService should be created via a factory method
var decoratorSetup = Setup.DecoratorWith(useDecorateeReuse: false);
c.RegisterDelegate<Lazy<IDecoratedService>, IDecoratedService>(DecorateService, setup: decoratorSetup);

// global scope is opened once on application startup
using (var globalScope = c.OpenScope())
{
// request scopes are created for each request
using (var requestScope = globalScope.OpenScope())
{
var ex = Assert.Throws<ContainerException>(() =>
{
var decorated = requestScope.Resolve<IDecoratedService>();
decorated.Hello();
});
Assert.AreEqual(Error.NameOf(Error.DependencyHasShorterReuseLifespan), ex.ErrorName);
}
}
}

static IDecoratedService DecorateService(Lazy<IDecoratedService> lazy)
{
WriteLine("CreateDecoratedService is called!");
return lazy.Value;
}

#if DEBUG
private static void WriteLine(string s) => TestContext.Progress.WriteLine(s);
#else
private static void WriteLine(string s) {}
#endif

public interface IUndecoratedService
{
Expand Down

0 comments on commit 0ef9d64

Please sign in to comment.