0

In summary:

  1. I've undefined of unknowed IProducerPlugin implementations on several assemblies located on a plugins folder.
  2. I've a Core object stores a list of current registered users.
  3. Core is Composition Root.

So, I need:

  1. To create as many IProducerPlugin inherited class objects as the number of registered users.
  2. When a new user is un/registered I need to create / release these objects.

In order to register my "plugins":

this.Kernel.Bind(b => b.FromAssembliesMatching("*")
            .SelectAllClasses()
            .InheritedFrom(typeof(Extensibility.IProducerPlugin))
            .BindAllInterfaces());

I'm not quite figuring out how to implement this.

Could you help me please?

I'll appreciate a LOT your help.

Jordi
  • 20,868
  • 39
  • 149
  • 333

2 Answers2

1

DI containers in general and Ninject in special are not suitable to add and remove new bindings to the container during runtime. Some, like Autofac, don't even allow adding bindings once the container is created. Ninject allows adding new bindings at any time, but you cannot, ever, remove them (*from some use cases there's Rebind, but that's not the same).

kernel.Release(object) is not removing the binding, it's only removing all references to the object that it holds. For example:

var foo = new object();
kernel.Bind<object>().ToConstant(foo);

to allow garbage collecting of foo you can do one of the following:

  • kernel.Release(foo);
  • kernel.Dispose(); kernel = null;

and exactly this is what kernel.Release(...) is for. Maybe you could also Release a singleton and thus force ninject to create a new one on the next request. But i don't know whether this really works, and if it does, it certainly is quite an unexpected hack.


So what you should do is manage the list/dictionary yourself. You can bind and inject the list/dictionary/manager what ever you call it using ninject, but you cannot have ninject manager the list itself.

BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • Thanks. The question was focused rather on the fact how to create the desired bindings. I've achieved this using concrete classes ([see this answer](http://stackoverflow.com/a/31533684/5003057)). However I've not figured out how to do something like this on a interface binding over convention... See my next answer. – Jordi Jul 21 '15 at 12:07
  • @Jordi basically the provider encapsulates the dictionary - which works if you never need to remove an entry. Otherwise it get's a bit more trickier. – BatteryBackupUnit Jul 21 '15 at 13:49
  • Thanks @BatteryBackupUnit. However, the problem is I perform a `GetAll` or a `Get`, NInject requests on my provider, ok, no problem. However, the information received on `Create` method embedded in context parameter doesn't contain any information about the concrete classes registered previously. This is the main problem (I've registered several concrete implementations of my `IProducerPlugin` interface, however, I'm not quite figuring out how to create instances of them on provider due this information is on anywhere. – Jordi Jul 22 '15 at 06:20
  • @Jordi An `IProvider` does not make sense with `GetAll` where individual items are bound. You can have an `IProvider` for an entire collection (the provider returning the collection), but then, it doesn't make sense to bind the collection **items** using ninject. – BatteryBackupUnit Jul 22 '15 at 08:58
0

I've managed to do something like that similar using this a IBindingGenerator interface method...

I've used .BindWith<>() binding method...

this.Kernel.Bind(b => b.FromAssembliesMatching("*")
            .SelectAllClasses()
            .InheritedFrom(typeof(Extensibility.IProducerPlugin))
            .BindWith<PluginBindingGenerator<Extensibility.IProducerPlugin>>()
        );

I've implemented a IBindingGenerator:

public class PluginBindingGenerator<T> : IBindingGenerator
{
    public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, Ninject.Syntax.IBindingRoot bindingRoot)
    {
        if (type != null && !type.IsAbstract && type.IsClass && typeof(T).IsAssignableFrom(type))
        {
            Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object> syntax = bindingRoot.Bind(typeof(Extensibility.IProducerPlugin)).ToProvider(new PluginProvider());
            yield return (Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>)syntax;
        }
    }
}

public class PluginProvider : IProvider<object>
{

    private System.Collections.Generic.Dictionary<Domain.Identity.ClientIdentity, Extensibility.IProducerPlugin> plugins;

And then, the provider:

    public PluginProvider()
    {
        this.plugins = new System.Collections.Generic.Dictionary<Domain.Identity.ClientIdentity, Extensibility.IProducerPlugin>();
    }

    public object Create(IContext ctx)
    {

        //... I don't know what to do here...

        return objects;
    }

    public Type Type
    {
        get { throw new NotImplementedException(); }
    }
}
Jordi
  • 20,868
  • 39
  • 149
  • 333