Reputation: 1725
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?
Upvotes: 6
Views: 5534
Reputation: 33306
In the web project run the following command from the Package Manager Console.
Install-Package Ninject.MVC3
You should end up with a NinjectWebCommon module in the App_Start folder.
Towards the bottom you can add your dependencies like below:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IPeopleRepository>().To<PeopleRepository>();
}
From your class library project run the following command:
Install-Package Ninject
This is how to inject a service with a repository from the class library:
public class PeopleService : IPeopleService
{
private readonly IPeopleRepository _peopleRepository;
[Inject]
public PeopleService(IPeopleRepository peopleRepository)
{
this._peopleRepository = peopleRepository;
}
}
Upvotes: 4
Reputation: 61795
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 be static
, 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 the Kernel
instance as its being constructed. That way your DLL is only bound to the interface of your CacheServiceResolver
.
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 and Bind
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 an IKernel
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:
Upvotes: 8