Skip to content

Commit abb5761

Browse files
author
maximv
committed
fixed: #239 WithUknownServiceResolver ignores ResolveMany
1 parent 62ebb50 commit abb5761

File tree

3 files changed

+126
-7
lines changed

3 files changed

+126
-7
lines changed

docs/DryIoc.Docs/RulesAndDefaultConventions.cs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,10 +652,69 @@ In addition you can use the rule to [select constructor with all resolvable para
652652
653653
### UnknownServiceResolvers
654654
655-
The rules is used as a last resort / fallback resolution strategy when no registration is found.
655+
**Obsolete** - please use the the `WithDynamicRegistrations` and `WithDynamicRegistrationsAsFallback` instead.
656656
657-
You may use this rule to implement on-demand registrations, or automatic concrete types registrations, etc.
657+
The `UnknownServiceResolvers` is **obsolete** Today because they did not support the other DryIoc features,
658+
(e.g. wrappers, decorators, `ResolveMany`) comparing to the normal registrations.
659+
The reason is because the `UnknownServiceResolvers` were implemented as a mechanism different from the registration resolution pipeline.
660+
The newer alternative is the `WithDynamicRegistrations` and the features based on it. See below.
658661
662+
Example of `ResolveMany` not working with the `UnknownServiceResolvers` and working with the `WithDynamicRegistrationsAsFallback`:
663+
664+
```cs md*/
665+
class ResolveMany_does_not_work_WithUnknownResolvers
666+
{
667+
[Test]public void Example_not_working()
668+
{
669+
var parent = new Container();
670+
parent.Register<IService, Service1>();
671+
parent.Register<IService, Service2>();
672+
673+
var child = new Container(Rules.Default.WithUnknownServiceResolvers(req =>
674+
new DelegateFactory(_ => parent.Resolve(req.ServiceType))));
675+
676+
// does not work
677+
var actual = child.ResolveMany<IService>();
678+
679+
// the result count is 0!
680+
Assert.AreEqual(0, actual.Count());
681+
}
682+
683+
[Test]public void Example_working()
684+
{
685+
var parent = new Container();
686+
parent.Register<IService, Service1>();
687+
parent.Register<IService, Service2>();
688+
689+
Rules.DynamicRegistrationProvider dynamicRegistration = (serviceType, serviceKey) =>
690+
new[]
691+
{
692+
new DynamicRegistration(new DelegateFactory(_ => parent.Resolve(serviceType,
693+
serviceKey is DefaultDynamicKey dk ? DefaultKey.Of(dk.RegistrationOrder) : null)))
694+
};
695+
696+
// we need a double dynamic registrations here because we have a two default services and
697+
// the service key translation is the "key" to distinguish between the services
698+
var child = new Container(Rules.Default.WithDynamicRegistrationsAsFallback(
699+
dynamicRegistration,
700+
dynamicRegistration));
701+
702+
// works
703+
var actual = child.ResolveMany<IService>().ToArray();
704+
705+
// 2 services are resolved
706+
Assert.AreEqual(2, actual.Length);
707+
CollectionAssert.AreEquivalent(new[] { typeof(Service1), typeof(Service2) },
708+
actual.Select(x => x.GetType()));
709+
}
710+
711+
interface IService { }
712+
class Service1: IService { }
713+
class Service2: IService { }
714+
}
715+
716+
/*md
717+
```
659718
660719
#### AutoFallbackDynamicRegistrations
661720

docs/DryIoc.Docs/RulesAndDefaultConventions.md

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,68 @@ In addition you can use the rule to [select constructor with all resolvable para
648648

649649
### UnknownServiceResolvers
650650

651-
The rules is used as a last resort / fallback resolution strategy when no registration is found.
651+
**Obsolete** - please use the the `WithDynamicRegistrations` and `WithDynamicRegistrationsAsFallback` instead.
652652

653-
You may use this rule to implement on-demand registrations, or automatic concrete types registrations, etc.
653+
The `UnknownServiceResolvers` is **obsolete** Today because they did not support the other DryIoc features,
654+
(e.g. wrappers, decorators, `ResolveMany`) comparing to the normal registrations.
655+
The reason is because the `UnknownServiceResolvers` were implemented as a mechanism different from the registration resolution pipeline.
656+
The newer alternative is the `WithDynamicRegistrations` and the features based on it. See below.
654657

658+
Example of `ResolveMany` not working with the `UnknownServiceResolvers` and working with the `WithDynamicRegistrationsAsFallback`:
659+
660+
```cs
661+
class ResolveMany_does_not_work_WithUnknownResolvers
662+
{
663+
[Test]public void Example_not_working()
664+
{
665+
var parent = new Container();
666+
parent.Register<IService, Service1>();
667+
parent.Register<IService, Service2>();
668+
669+
var child = new Container(Rules.Default.WithUnknownServiceResolvers(req =>
670+
new DelegateFactory(_ => parent.Resolve(req.ServiceType))));
671+
672+
// does not work
673+
var actual = child.ResolveMany<IService>();
674+
675+
// the result count is 0!
676+
Assert.AreEqual(0, actual.Count());
677+
}
678+
679+
[Test]public void Example_working()
680+
{
681+
var parent = new Container();
682+
parent.Register<IService, Service1>();
683+
parent.Register<IService, Service2>();
684+
685+
Rules.DynamicRegistrationProvider dynamicRegistration = (serviceType, serviceKey) =>
686+
new[]
687+
{
688+
new DynamicRegistration(new DelegateFactory(_ => parent.Resolve(serviceType,
689+
serviceKey is DefaultDynamicKey dk ? DefaultKey.Of(dk.RegistrationOrder) : null)))
690+
};
691+
692+
// we need a double dynamic registrations here because we have a two default services and
693+
// the service key translation is the "key" to distinguish between the services
694+
var child = new Container(Rules.Default.WithDynamicRegistrationsAsFallback(
695+
dynamicRegistration,
696+
dynamicRegistration));
697+
698+
// works
699+
var actual = child.ResolveMany<IService>().ToArray();
700+
701+
// 2 services are resolved
702+
Assert.AreEqual(2, actual.Length);
703+
CollectionAssert.AreEquivalent(new[] { typeof(Service1), typeof(Service2) },
704+
actual.Select(x => x.GetType()));
705+
}
706+
707+
interface IService { }
708+
class Service1: IService { }
709+
class Service2: IService { }
710+
}
711+
712+
```
655713

656714
#### AutoFallbackDynamicRegistrations
657715

src/DryIoc/Container.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,12 +1693,12 @@ private KV<object, Factory>[] CombineRegisteredWithDynamicFactories(
16931693
var resultFactories = registeredFactories;
16941694
var dynamicRegistrationProviders = Rules.DynamicRegistrationProviders;
16951695

1696-
// Assign unique continious keys across all of dynamic providers,
1696+
// Assign unique continuous keys across all of dynamic providers,
16971697
// to prevent duplicate keys and peeking the wrong factory by collection wrappers
16981698
// NOTE: Given that dynamic registration always return the same implementation types in the same order
16991699
// then the dynamic key will be assigned deterministically, so that even if `CombineRegisteredWithDynamicFactories`
17001700
// is called multiple times during the resolution (like for `ResolveMany`) it is possible to match the required factory by its order.
1701-
var dynamicKey = DefaultDynamicKey.Value;
1701+
DefaultDynamicKey dynamicKey = null;
17021702
for (var i = 0; i < dynamicRegistrationProviders.Length; i++)
17031703
{
17041704
var dynamicRegistrationProvider = dynamicRegistrationProviders[i];
@@ -1720,7 +1720,9 @@ private KV<object, Factory>[] CombineRegisteredWithDynamicFactories(
17201720
resultFactories = dynamicRegistrations.Match(x =>
17211721
x.Factory.FactoryType == factoryType &&
17221722
x.Factory.ValidateAndNormalizeRegistration(serviceType, serviceKey, false, Rules),
1723-
x => KV.Of(x.ServiceKey ?? (dynamicKey = dynamicKey.Next()), x.Factory));
1723+
x => KV.Of(
1724+
x.ServiceKey ?? (dynamicKey = dynamicKey?.Next() ?? DefaultDynamicKey.Value),
1725+
x.Factory));
17241726
continue;
17251727
}
17261728

0 commit comments

Comments
 (0)