Ninject

Nuget packages: Ninject, Version 3.2.2

An obsessive focus on simplicity and ease of use. An example from their site:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Samurai {
public IWeapon Weapon { get; private set; }
public Samurai(IWeapon weapon)
{
this.Weapon = weapon;
}
}

// Then in the module
// I would put this `WarriorModule` in `Business/Plumbing/Ninject`
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();

// The above is a Fluent API so you can then scope as needs be
// .InSingletonScope();
// .InTransientScope();
}
}

When Injected Exactly Into

This binding also allows you to bind an exact instance of something WhenInjectedExactlyInto so if you have a set of rules and your class needs a specific rule, you can inject it:

1
Bind<IRules>().To<SomeRule>().WhenInjectedExactlyInto<ConsumerClass>();

Bind All Interfaces

If you have 100’s of services and they will be named as IServiceName for the interface and ServiceName for the implementation you can leverage refection and BindAllInterfaces to bind these for you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var patterns = new[]
{
"SweetApp.dll",
"SweetApp.Admin.dll"
};

var typesToExclude = new List<Type>
{
typeof (RubbishService),
typeof (RubbishService2)
};

.Bind(x => x.FromAssembliesMatching(patterns)
.SelectAllClasses()
.Excluding(typesToExclude)
.BindDefaultInterface());

/* Ninject.Extensions.Conventions.3.2.0

FromAssembliesMatching
-> Scans the assemblies that matching one of the given assembly name pattern.

SelectAllClasses
-> Selects all none abstract classes.

Excluding
-> Excludes the given types

BindDefaultInterface
-> Binds the default interface of the given types to the type. e.g. Foo : IFoo
*/

Contextual Binding

Contextual binding allows more than one binding for a type using .Named

I dont think this is the best way to do things as the consumer (maybe a repository or service) then really has muiltiple concearns. (Well for my example anyway) The examples below were adapted from github.com/ninject and are for a scenario where 2 Launch Darkly (feature management client) projects need to be injected into the same repository. Each project has its own SDK Key so the client needs to be instantiated with its correct key.

Create an enum, for reasons :)

1
2
3
4
5
public enum LaunchDarklyProjectEnum
{
ProjectOne,
ProjectTwo
}

The IOC is then setup. InSingletonScope is fine as there is no state and each request should get the same instance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Bind<ILdClient>()
.ToMethod(x =>
{
var sdkKeyProjectOne = "sdk-0000000000000000";
return new LdClient(sdkKeyProjectOne);
})
.InSingletonScope()
.Named(LaunchDarklyProjectEnum.ProjectOne);

Bind<ILdClient>()
.ToMethod(x =>
{
var sdkKeyProjectTwo = "sdk-1111111111111111";
return new LdClient(sdkKeyProjectTwo);
})
.InSingletonScope()
.Named(LaunchDarklyProjectEnum.ProjectTwo);

Then when resolved you indicate the name you want to use in the given context:

1
2
3
4
5
6
7
8
9
10
11
12
public class LdFeatureRepository {
private readonly ILdClient _ldClientProjectOne;
private readonly ILdClient _ldClientProjectTwo;

public LdFeatureRepository(
[Named(LaunchDarklyProjectEnum.ProjectOne)] ILdClient ldClientProjectOne,
[Named(LaunchDarklyProjectEnum.ProjectTwo)] ILdClient ldClientProjectTwo)
{
_ldClientProjectOne = ldClientProjectOne;
_ldClientProjectTwo = ldClientProjectTwo;
}
}

References