Jordi
Jordi

Reputation: 23277

NInject: Create instances per user/session on convention binding

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.

Upvotes: 0

Views: 272

Answers (2)

Jordi
Jordi

Reputation: 23277

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(); }
    }
}

Upvotes: 0

BatteryBackupUnit
BatteryBackupUnit

Reputation: 13243

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.

Upvotes: 1

Related Questions