ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(standardKernel));

1,197 views
Skip to first unread message

Le

unread,
Feb 15, 2012, 6:38:30 PM2/15/12
to ninject
When registering the adapter (NinjectServiceLocator)

e.g:
ServiceLocator.SetLocatorProvider(() => new
NinjectServiceLocator(standardKernel));

to use ServiceLocator with an MVC3 application, and the MVC runtime
asks the IDependencyResolver for an registered instance e.g.
IControllerFactory, ServiceLocator will return a
"Microsoft.Practices.ServiceLocation.ActivationException". What should
happen here is ServiceLocator (using the NinjectServiceLocator) should
return null if a request for a particular instance isn't found so that
the MVC runtime can fallback and return the default instance which in
our case is the DefaultControllerFactory.

This issue is documented here:
http://blog.longle.net/2012/02/15/wrapping-the-ninject-kernel-with-servicelocator/

Any ideas?

Remo Gloor

unread,
Feb 15, 2012, 6:42:31 PM2/15/12
to nin...@googlegroups.com

Jarrett Meyer

unread,
Feb 15, 2012, 6:55:03 PM2/15/12
to nin...@googlegroups.com
(Remo beat me to it.)

Microsoft's service locator doesn't really work with MVC's dependency resolver. In fact, when this feature was first being developed, there was plenty of discussion about using service location instead of dependency resolution. Plus, there's issues with Interface Segregation Principle going on here. (Classes shouldn't depend on interfaces they don't use. DR has 2 only methods. CSL has 6. This was quite the hot topic back in the day.)

As for implementation, ServiceLocator.Current.GetInstance(type) throws an exception if the type cannot be resolved. In your case, the specific problem is IControllerFactory instance. My bet is that you didn't wire that up in your kernel bindings. (Nor should you.) DependencyResolver.Current.GetService(type) needs to return null - not throw an exception. When types are not found, especially for IControllerFactory and other MVC-specific implementations, MVC needs to use DefaultControllerFactory, etc.

It's really easy to write your own DR implementation, if you don't want to rely on Ninject.MVC3. It's one class.

public NinjectDependencyResolver : IDependencyResolver
{
  private readonly IKernel kernel;
  public NinjectDependencyResolver(IKernel kernel)
  {
    this.kernel = kernel;
  }
  public virtual object GetService(Type type)
  {
    return kernel.TryGet(type); // TryGet returns null, Get throws
  }
  public virutal IEnumerable<object> GetServices(Type type)
  {
    return kernel.GetAll(type);
  }
}

Or, you could wire up all of the MVC-specific stuff inside your Ninject kernel. But that sucks, and exposes you to a lot of work that you don't care about and has nothing to do with your application.

But yeah, like Remo said, use Ninject.MVC3 - problem solved.
--
Jarrett Meyer
Email: jarret...@gmail.com
Web: JarrettMeyer.com
Twitter: @jarrettmeyer




--
You received this message because you are subscribed to the Google Groups "ninject" group.
To post to this group, send email to nin...@googlegroups.com.
To unsubscribe from this group, send email to ninject+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ninject?hl=en.


Remo Gloor

unread,
Feb 15, 2012, 7:15:58 PM2/15/12
to nin...@googlegroups.com

Jarret your dependency resolver implementation is wrong

1.       It swallows activation exceptions which prevents having good stack traces

2.       You can get strange behaviors in some situations.

                See https://github.com/ninject/ninject.web.mvc/commit/ebc359a6aa5e13b32cd2bca509037c11a690309f

Unfortunately you can find this wrong implementation on way too many blog posts producing a lot of bug reports.

The obvious implementation is not the correct unfortunately.

 

Remo

Reply all
Reply to author
Forward
0 new messages