To start I'm using Ninject 1.5. I have two projects: Web project and a Class library. My DI configuration is within the Web project. Within my class library I have the following defined:
public interface ICacheService<T>
{
string Identifier { get; }
T Get();
void Set( T objectToCache, TimeSpan timeSpan );
bool Exists();
}
And then a concrete class called CategoryCacheService.
In my web project I bind the two:
Bind( typeof( ICacheService<List<Category>> ) ).To( typeof(CategoryCacheService)).Using<SingletonBehavior>();
In my class library I have extension methods for the HtmlHelper class, for example:
public static class Category
{
[Inject]
public static ICacheService<List<Category>> Categories { get; set; }
public static string RenderCategories(this HtmlHelper htmlHelper)
{
var c = Categories.Get();
return string.Join(", ", c.Select(s => s.Name).ToArray());
}
}
I've been told that you cannot inject into static properties, instead I should use Kernel.Get<>() - However... Since the code above is in a class library I don't have access to the Kernel. How can I get the Kernel from this point or is there a better way of doing this?
In the web project run the following command from the Package Manager Console.
You should end up with a NinjectWebCommon module in the App_Start folder.
Towards the bottom you can add your dependencies like below:
From your class library project run the following command:
This is how to inject a service with a repository from the class library:
Good question to ask.
Half the idea of using DI is to remove the concern/fine tuning of the instancing behavior from the code under injection. Therefore, it may make more sense to change the
Category
class to no longer bestatic
, declare its dependencies in a ctor and let the client code stitch it together.Regarding how to access it if you're really sure its a good idea... Generally the idea in your case would be to create a
CacheServiceResolver
and register it [in your Web Project]. Then pass it theKernel
instance as its being constructed. That way your DLL is only bound to the interface of yourCacheServiceResolver
.The other approach often used is to have a last-resort 'Service Locator' facility somewhere global, which exposes a 'GlobalGet'. But that's generally A Bad Idea and should only be used for temporary Duct Taping purposes.
The other thing to look at is the Common Service Locator, which will allow one to make a library container-neutral, though outside of EL, you wont find a lot of usage as you shouldnt really show your container.
The other option is to demand a
Func<T>
factory method andBind
that to a lambda that resolves it, extracting that lookup from your code.EDIT: In Ninject 2, there's no need to explicitly pass in
Kernel
instances as I've said - one can simply ask for anIKernel
in your ctor and you'll get it, regardless of whether the resolution request expclicitly passes one in.EDIT 2: Really unhappy with my answer, have tried to make it more general without butchering it too much. Summary is that the desirable options are generally in the following in order: