Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject 2.0: Property Injection without attribute

Is there a way to use Property Injection in Ninject 2 without using the [Inject] attribute? This creates a dependency to Ninject in the class that will be wired using it and I prefer to avoid having unneeded dependencies to my IoC container, that's why I end up using Constructor Injection more often.

I guess the same applies to Method Injection

like image 925
t3mujin Avatar asked Jul 12 '10 18:07

t3mujin


3 Answers

I followed Ruben's tip and posted a small blog post on how to achieve this, but here's the quick answer:

Create a custom attribute:

public class InjectHereAttribute : Attribute
{
}

The target class will now look like this:

public class Samurai
{
    [InjectHere]        
    public IWeapon Context { get; set; }
}

Now Ninject must be configured to use the custom attribute, this can be done by creating an implementation of IInjectionHeuristic that recognizes the custom attribute:

public class CustomInjectionHeuristic : NinjectComponent, IInjectionHeuristic, INinjectComponent, IDisposable
{
    public new bool ShouldInject(MemberInfo member)
    {
        return member.IsDefined(
          typeof(InjectHereAttribute),
          true);
    }
}

And finally add this behavior to the Ninject Kernel using the Components collection, it will run along the existing components, namely the default implementation of IInjectionHeuristic, which means either the default or the custom attribute can be used.

// Add custom inject heuristic
kernel.Components.Add<IInjectionHeuristic, CustomInjectionHeuristic>();
like image 166
t3mujin Avatar answered Nov 14 '22 03:11

t3mujin


You can pass in another [attribute] type to the Kernel upon creation which can be used instead of InjectAttribute, but you'll still have to reference something centrally OOTB.

There was a similar question very recently about doing PI without attributes - there's no OOTB (as in directly on the fluent configuration interface) to put in a custom scanner but the extensibility points (you add a component that implements a Ninject interface as you build your Kernel that dictates how that aspect is to be work if looking for a given attribute isnt't what you want) are in there to determine where to inject based on Convention over Configuration - there's nothing stopping you amending the scanning to be based on just an attribute name (so it doesnt necessarily have to live in a central location).

Note that, in general, constructor injection is good for lots of reasons anyway, including this one, and keeping you code container agnostic is important (even if you're currently happy with one!)

like image 4
Ruben Bartelink Avatar answered Nov 14 '22 03:11

Ruben Bartelink


I was able to accomplish this using a Heuristic class:

public sealed class MyInjectionHeuristic : NinjectComponent, IInjectionHeuristic
{
        private static readonly IList<Type> 
            _propertyInjectible = 
                new List<Type>
                {
             typeof(IMyService),
                };

                    /// <summary>
      /// Returns a value indicating whether the specified member should be injected.
      /// </summary>
      /// <param name="member">The member in question.</param>
      /// <returns><c>True</c> if the member should be injected; otherwise <c>false</c>.</returns>
      public bool ShouldInject(MemberInfo member)
      {
       var info = member as PropertyInfo;

       if( member == null || info == null )
        return false;

       if (info.CanWrite)
        return _propertyInjectible.Contains(info.PropertyType);

       if( this.Settings == null )
        return false;

       var propList = member.GetCustomAttributes(this.Settings.InjectAttribute, true);

       return propList.Length > 0;
      }
}

When creating your kernel:

var heuristics = _kernel.Components.Get<ISelector>().InjectionHeuristics;
   heuristics.Add(new MyInjectionHeuristic());

Simple add additional types to the IList when you want to inject other types via properties.

like image 3
JPM Avatar answered Nov 14 '22 02:11

JPM