Making Visual Studio services available in a Ninject Kernel is actually a fairly easy task. All you need to do is to implement an IMissingBindingResolver
(let’s call it VsServiceResolver
) and register it to the kernel with
kernel.Components.Add<IMissingBindingResolver, VsServiceResolver>();
Since we don’t create the resolver instance ourselves, we cannot pass it a reference to the current package for service lookup. Instead, we need to fall back to resolving services by a static call to Package.GetGlobalService()
. This implies, that VsPackage-local services cannot be retrieved by this approach.
The resolver implementation itself is straightforward:
class VsServiceResolver : NinjectComponent, IMissingBindingResolver
{
public IEnumerable<IBinding> Resolve(Multimap<Type, IBinding> bindings, IRequest request)
{
var service = Package.GetGlobalService(request.Service);
if (service != null)
{
return new[]
{
new Binding(requestType)
{
ProviderCallback =
context =>
{
return new ConstantProvider<object>(service);
}
}
};
}
return Enumerable.Empty<IBinding>();
}
}
Note that this resolver implementation is rather naive and probably not optimal in terms of performance, since it will try to resolve a service even if the request.Service
type is not a service interface. If you want to make only certain service available to the kernel, I’d recommend you to check whether the requested type is one of the respective service interfaces. A more general approach could be to check if the request.Service
‘s name starts with a capital S, since most Visual Studio service interfaces follow this convention. Then, however, you have to take care of special cases, such as the DTE
interface.