Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC3, Ninject, MvcSiteMapProvider - How to inject dependency to overridden method

I have an MVC3 application that is using Ninject and MvcSiteMapProvider.

I have created this class which MvcSiteMapProvider uses to dynamically add nodes to my sitemap:

public class PageNodeProvider : DynamicNodeProviderBase
{
    public override IEnumerable<DynamicNode> GetDynamicNodeCollection()
    {            
         // need to get repository instance
         var repository = // how do I get this???

         foreach (var item in repository.GetItems())
         {
              yield return MakeDynamicNode(item);
         }
    }
}

The MvcSiteMapProvider instantiates this type itself, so I'm not sure how to inject my repository into it.

I thought about using service location by getting a handle on my kernel and calling Get<Repository>() in the method. But, I saw this property when looking at the definition of NinjectHttpApplication:

    // Summary:
    //     Gets the kernel.
    [Obsolete("Do not use Ninject as Service Locator")]
    public IKernel Kernel { get; }

Do not use Ninject as Service Locator ?! How else am I supposed to do this? I then found this question here on stackoverflow and all answers say don't use Service Location.

What am I supposed to do?

like image 610
Ronnie Overby Avatar asked Oct 28 '11 19:10

Ronnie Overby


2 Answers

This seems to be another chapter from the book "Why providers are bad design?". You have the same problem as with any kind of ASP.NET providers. There are no really good and satisfying solutions for them. Just hacks.

I think the best option you have is to fork the project and change the DefaultSiteMapProvider to use DepencencyResolver instead of the Activator and provide the implementation back to the community. Then you can use constructor injection in your PageNodeProvider implementation. This will solve the problem once for all types and everyone.

Of course you could also use the DependencyResolver just in your implementation. But this is by far not the best solution because you should get the instances as close to the root as possible, it makes testing more complicated and it solves the problem just for you.

like image 154
Remo Gloor Avatar answered Oct 22 '22 22:10

Remo Gloor


Even though I see that you've decided to ditch the provider altogether, I'd like to elaborate on using the DependencyResolver. Basically, you can manually get the correct repository instance via Ninject using

var repository = DependencyResolver.Current.GetService<IRepository>();

This is less robust, as you have to maintain this as well as the NinjectMVC3.cs class should the stuff change, and it is a bit more complicated to test.

like image 40
Moshe Avatar answered Oct 23 '22 00:10

Moshe