Ninject register by convention with names

288 Views Asked by At

Is there a way to register with Ninject, using conventions, all classes that implement a certain interface, associated with each class' name?

interface IClientCodeValidator
{
    string ValidateClientCode(params IXpressionNode[] customParameters);
    string ValidatorName { get; }
}

public class Client1CodeValidator: IClientCodeValidator
{
    public Client1CodeValidator()
    {
         this.ValidatorName = "Client1";
    }
}

public class Client2CodeValidator: IClientCodeValidator
{
    public Client2CodeValidator()
    {
         this.ValidatorName = "Client2";
    }
}

Bind<IClientCodeValidator>()
        .To.ItsClasses()
        .InSingletonScope()
    .Named(*c => c.ValidatorName*); <--

Then later

Container.Instance.Get<IClientCodeValidator>(clientName.ToUpper())
1

There are 1 best solutions below

2
Dave Thieben On

The way you're going about this is an anti-pattern called Service Locator. The recommended approach would be to use Abstract Factory instead. In that pattern, you would have an additional interface that is responsible for resolving the correct concrete implementation. For your example:

interface IClientCodeValidatorFactory
{
    IClientCodeValidator GetFor(string client);
}

public class ClientCodeValidatorFactory : IClientCodeValidatorFactory
{
    private readonly IKernel _kernel;

    public ClientCodeValidatorFactory(IKernel kernel)
    {
        _kernel = kernel;
    }

    public IClientCodeValidator GetFor(string client)
    {
        // load from your configuration how client names are associated to Validators
        return _kernel.Get<IClientCodeValidator>(validatorName)
    }
}

this way you can inject IClientCodeValidatorFactory into your constructor and avoid using Container.Instance altogether.

then you can use Ninject.Extensions.Conventions to automatically bind validators to the interface:

kernel.Bind( x => x
    .FromThisAssembly()
    .SelectAllClasses().InheritedFrom<IClientCodeValidator>()
    .BindAllInterfaces()
    .Configure(b => b.InSingletonScope()));