Ninject: Default & specific bindings for a Generic class
I have an abstract class:
public abstract class Validator<T> : IValidator
and a couple of classes that implement this class for specific purposes, e.g.
public sealed class NewsValidator : Validator<News>
Now using Ninject i want to do Dependency Injection like the following (this particular code is NOT working):
Bind<Validator<News>>().To<NewsValidator>();
Bind(typeof(Validator<>)).To(typeof(NullValidator<>));
So what I want to achieve is that
Validator<News>
Should be bound to the Class "NewsValidator", but if any other not-bound version of this class is requested, say
Validator<Article>
Validator<SomethingElse>
that should be bound to a default Class (NullValidator). Using the code used above throws an Exception, though, because it binds the Validator < News > both to the NewsValidator as well as to the NullValidator.
How could I implement this? Particular types of the generic class should be bound to individual classes. All other types of the generic class that were not explicitly bound should be bound to a default class.
Would be really glad about a couple of suggestio开发者_开发技巧ns! Thanks!
You could create a custom implementation of IMissingBindingResolver.
Whenever the kernel fails to resolve a binding for a requested service it delegates to the HandleMissingBinding method (this is true for any kernel derived from KernelBase). The HandleMissingBinding method will ask every missing binding resolver if it can create a binding for the requested service. The bindings returned by the resolvers, if any, will be added to the kernel.
Note that any binding created by a missing binding resolver will be added to the kernel as an implicit binding. This could have implication on your application. For example, if you have a mixture of explicit and implicit bindings for a service, resolving these bindings, i.e. kernel.GetAll<TService>()
, only resolves explicit bindings. However, if all bindings are implicit they will all be resolved.
Ninject has two standard implementations of IMissingBindingResolver:
- DefaultValueBindingResolver
- SelfBindingResolver
Let's implement a custom resolver for the null validators.
public class MissingValidatorResolver : NinjectComponent, IMissingBindingResolver
{
public IEnumerable<IBinding> Resolve(
Multimap<Type, IBinding> bindings, IRequest request)
{
var service = request.Service;
if (!typeof(IValidator).IsAssignableFrom(service))
{
return Enumerable.Empty<IBinding>();
}
var type = service.GetGenericArguments()[0];
var validatorType = typeof(NullValidator<>).MakeGenericType(type);
var binding = new Binding(service)
{
ProviderCallback = StandardProvider.GetCreationCallback(validatorType)
};
return new[] { binding };
}
}
Now the following test (using xUnit.net) passes.
[Fact]
public void ShouldResolveNonBoundValidatorDerivedFromValidatorAsNullValidator()
{
var kernel = new StandardKernel();
kernel.Components.Add<IMissingBindingResolver, MissingValidatorResolver>();
var validator = kernel.Get<Validator<Article>>();
Assert.IsType<NullValidator<Article>>(validator);
}
精彩评论