Geeks With Blogs
AngelEyes on .Net Tips, tricks and WTFs about Asp .Net, SQL Server and the likes.
Note: This post was edited on 21st December 2011, after the first comment was left by Remo Gloor .


Using Ninject in a classic DI scenario, means that only the entry point of you code should have knowledge about Ninject. This is different than using it as a Service Locator, where either
  • all classes know about the IoC Container (Ninject, in this case) and access it, meaning that every class is implicitly coupled with it.
  • or, you have to pass the Service Locator as an argument to every class's constructor, which means adding a lot of code and having classes that don't use the SL directly know about it, since they must pass it along to classes they use.
So your code-entry point configures the Kernel to be used, according to its scenario. Then what?
Well, then it uses the IoC Container to instantiate a class, or several classes, and that's it. Behind the scenes, every class called by those classes, doesn't know about the IoC Container, but declares its dependencies in its constructor. When the class is instantiated, the IoC Container will recognize the dependencies and attempt to resolve them, i.e. instantiate the classes which this class needs.

Note these following cases:
  • Class A depends on class B, but only uses it in specific situations.
  • Class A needs to return a type of class B.
  • Class A depends on Class B, but the configuration of Class B will only be known at run-time.
  • Class A will need several instances of class B, but the number of instances will only be known at run-time. 
In these cases, you might want to pass a factory method to class A's constructor. This method can be used by class A to instantiate class B. So how do you do that?

Let's use a real-life example. Class B, in this example, is AuditManager, and it implements an interface called IAuditManager.
First, we declare the factory method in the constructor of the dependent class (called "Class A", above):
...
private readonly Func <IAuditManager> _auditManagerFactory;

public SomeConstructor(Func<IAuditManager> auditManagerFactory) 
{
     _auditManagerFactory = auditManagerFactory;
}
...


As you can see, we're using Func<> to declare the delegate for the factory method.
To use the method, we simply invoke it:

   var auditManager= _auditManagerFactory();     
   auditManager.AuditSomething();


And this is how to bind the method, in the NinjectModule:

Bind<Func<IClassB>>()
.ToMethod(ctx => () => ctx.Kernel.Get<ClassB>());


Posted on Monday, December 12, 2011 5:19 PM | Back to top


Comments on this post: A short summary about DI and using Ninject not as a Service Locator

# re: A short summary about DI and using Ninject not as a Service Locator
Requesting Gravatar...
Thanks for your blog post. Here are some thoughts how I see this topic.

In my opinion the only valid scenario is a mixure of 1 and 2 in your example. An expensive dependency that is rarely used. And in this case for most situations Lazy fits better than Func.

Late creation of inexpensive rarely used dependencies has no benefit imo. And if an expensive dependency is used often then you can create it at startup because it will just postpone the heavy load for a short time and for users it is better to wait a bit longer at start up than when doing interactions with the system.

For point 3 a return value should only be a DTO. DTO's shouldn't be created using an IoC container. Objects containing business logic should be retrieved from the IoC container (using a factory as explained here) and not through other objects.

But you missed 2 other scenarios:
1. Objects that need a configuration which is unknown at the time the owner is created.
2. If you don't know how many instances you will need. E.g. a processor for some requests and you want to run several processors parallel for different requests.

In these cases you want to use a factory as explained in this blog post. I prefer interfaces as factories instead of Func as they are more descriptive especially when taking parameters.

The next version of Ninject will support all these facotry types with Ninject.Extensions.Factory See https://github.com/ninject/ninject.extensions.factory More details on this extension will follow soon.
Left by Remo Gloor on Dec 13, 2011 8:56 PM

# @Remo
Requesting Gravatar...
Thanks a lot for your comment, Remo!
First, I totally agree with your approach.

1. Regarding the use of "Lazy", I actually have not got around to implementing that - can you post a link to an example?

2. Why should a return value only be a DTO? Obviously "DTO's shouldn't be created using an IoC container", but why not return an actual object?

3. Regarding "Factory vs. Func", I'll have to check out the next Ninject version, when it's declared stable, and see if the syntax is "user friendly". Also, do you have any info on release time, and when "more details" will follow?
Left by AngelEyes on Dec 14, 2011 10:48 AM

Your comment:
 (will show your gravatar)


Copyright © AngelEyes | Powered by: GeeksWithBlogs.net