diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 24e426cf..07179af2 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -2,6 +2,9 @@ Version 2.4.0.0 --------------- - Added: Support for default parameters. If not explicit binding exists for a dependency but there is default value defined it is uesd instead. - Added: Support to define the constructor and constructor arguments using ToConstructor "to" overload +- Added: WhenInjectedExactlyInto When overload: Matches only if the target is exactly the specified type. This was the behavior of WhenInjectedInto in Ninject 2.2. +- Added: WhenAnyAnchestorNamed. Matches if any of the anchestor bindings is named with the specified name. +- Changed: WhenInjectedInto matches also if the target derives from the specified type. - Changed: ToConstant bindings are in singleton scope by default - Changed: Separate project for medium trust environments. - Changed: Open generic bindings can be overwritten by closed generic bindings diff --git a/src/Ninject.Test/Integration/ConditionalBindingTests.cs b/src/Ninject.Test/Integration/ConditionalBindingTests.cs index e5e678ff..c19453d7 100644 --- a/src/Ninject.Test/Integration/ConditionalBindingTests.cs +++ b/src/Ninject.Test/Integration/ConditionalBindingTests.cs @@ -1,5 +1,6 @@ namespace Ninject.Tests.Integration { + using System; using System.Linq; using FluentAssertions; using Ninject.Tests.Fakes; @@ -132,5 +133,52 @@ public void GivenOnlyImplicitBindings_AllBindingsWillResolve() result.Should().Contain(shortSword); result.Should().Contain(shuriken); } + + [Fact] + public void WhenInjectedIntoAppliesToBaseTypes() + { + kernel.Bind().To(); + kernel.Bind().To().WhenInjectedInto(); + + var warrior = kernel.Get(); + + warrior.Weapon.Should().BeOfType(); + } + + [Fact] + public void WhenInjectedExactlyIntoAppliesNotToBaseTypes() + { + kernel.Bind().To(); + kernel.Bind().To().WhenInjectedExactlyInto(); + + Action getWarrior = () => kernel.Get(); + + getWarrior.ShouldThrow(); + } + + [Fact] + public void WhenInjectedExactlyIntoAppliesToServiceType() + { + kernel.Bind().To(); + kernel.Bind().To().WhenInjectedExactlyInto(); + + var warrior = kernel.Get(); + + warrior.Weapon.Should().BeOfType(); + } + + [Fact] + public void WhenAnyAnchestorNamedAppliesToGrandParentAndParent() + { + const string Name = "SomeName"; + kernel.Bind().ToSelf().Named(Name); + kernel.Bind().To(); + kernel.Bind().To().WhenAnyAnchestorNamed(Name); + + var barack = kernel.Get(); + + barack.Weapon.Should().BeOfType(); + barack.Warrior.Weapon.Should().BeOfType(); + } } } \ No newline at end of file diff --git a/src/Ninject/Planning/Bindings/BindingBuilder.cs b/src/Ninject/Planning/Bindings/BindingBuilder.cs index 25e17f97..09db2ea6 100644 --- a/src/Ninject/Planning/Bindings/BindingBuilder.cs +++ b/src/Ninject/Planning/Bindings/BindingBuilder.cs @@ -186,6 +186,7 @@ public IBindingInNamedWithOrOnSyntax When(Func condition) /// /// Indicates that the binding should be used only for injections on the specified type. + /// Types that derive from the specified type are considered as valid targets. /// /// The type. public IBindingInNamedWithOrOnSyntax WhenInjectedInto() @@ -195,9 +196,33 @@ public IBindingInNamedWithOrOnSyntax WhenInjectedInto() /// /// Indicates that the binding should be used only for injections on the specified type. + /// Types that derive from the specified type are considered as valid targets. /// /// The type. public IBindingInNamedWithOrOnSyntax WhenInjectedInto(Type parent) + { + Binding.Condition = r => r.Target != null && parent.IsAssignableFrom(r.Target.Member.ReflectedType); + return this; + } + + /// + /// Indicates that the binding should be used only for injections on the specified type. + /// The type must match exactly the specified type. Types that derive from the specified type + /// will not be considered as valid target. + /// + /// The type. + public IBindingInNamedWithOrOnSyntax WhenInjectedExactlyInto() + { + return WhenInjectedExactlyInto(typeof(TParent)); + } + + /// + /// Indicates that the binding should be used only for injections on the specified type. + /// The type must match exactly the specified type. Types that derive from the specified type + /// will not be considered as valid target. + /// + /// The type. + public IBindingInNamedWithOrOnSyntax WhenInjectedExactlyInto(Type parent) { Binding.Condition = r => r.Target != null && r.Target.Member.ReflectedType == parent; return this; @@ -290,6 +315,30 @@ public IBindingInNamedWithOrOnSyntax WhenParentNamed(string name) return this; } + /// + /// Indicates that the binding should be used only when the service is being requested + /// by a service bound with the specified name or any of its anchestor services bound with the specified name. + /// + /// The name to expect. + public IBindingInNamedWithOrOnSyntax WhenAnyAnchestorNamed(string name) + { + Binding.Condition = r => IsAnyAnchestorNamed(r, name); + return this; + } + + private static bool IsAnyAnchestorNamed(IRequest request, string name) + { + var parentContext = request.ParentContext; + if (parentContext == null) + { + return false; + } + + return + string.Equals(parentContext.Binding.Metadata.Name, name, StringComparison.Ordinal) || + IsAnyAnchestorNamed(parentContext.Request, name); + } + /// /// Indicates that the binding should be registered with the specified name. Names are not /// necessarily unique; multiple bindings for a given service may be registered with the same name. diff --git a/src/Ninject/Syntax/BindingSyntax.cs b/src/Ninject/Syntax/BindingSyntax.cs index 248b484d..a7acb225 100644 --- a/src/Ninject/Syntax/BindingSyntax.cs +++ b/src/Ninject/Syntax/BindingSyntax.cs @@ -103,16 +103,34 @@ public interface IBindingWhenSyntax : IBindingSyntax /// /// Indicates that the binding should be used only for injections on the specified type. + /// Types that derive from the specified type are considered as valid targets. /// /// The type. IBindingInNamedWithOrOnSyntax WhenInjectedInto(); /// /// Indicates that the binding should be used only for injections on the specified type. + /// Types that derive from the specified type are considered as valid targets. /// /// The type. IBindingInNamedWithOrOnSyntax WhenInjectedInto(Type parent); + /// + /// Indicates that the binding should be used only for injections on the specified type. + /// The type must match exactly the specified type. Types that derive from the specified type + /// will not be considered as valid target. + /// + /// The type. + IBindingInNamedWithOrOnSyntax WhenInjectedExactlyInto(); + + /// + /// Indicates that the binding should be used only for injections on the specified type. + /// The type must match exactly the specified type. Types that derive from the specified type + /// will not be considered as valid target. + /// + /// The type. + IBindingInNamedWithOrOnSyntax WhenInjectedExactlyInto(Type parent); + /// /// Indicates that the binding should be used only when the class being injected has /// an attribute of the specified type. @@ -161,6 +179,13 @@ public interface IBindingWhenSyntax : IBindingSyntax /// /// The name to expect. IBindingInNamedWithOrOnSyntax WhenParentNamed(string name); + + /// + /// Indicates that the binding should be used only when the service is being requested + /// by a service bound with the specified name or any of its anchestor services bound with the specified name. + /// + /// The name to expect. + IBindingInNamedWithOrOnSyntax WhenAnyAnchestorNamed(string name); } ///