NInject IBindingGenerator and ToProvider

2019-08-31 02:24发布

问题:

I've created this code:

public class AddonsModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        this.Bind(b => b.FromAssembliesMatching("*")
            .SelectAllClasses()
            .InheritedFrom(typeof(UIExtensibility.AbstractAddon))
            .BindWith(new AddonBindingGenerator())
        );
    }

    private class AddonBindingGenerator : IBindingGenerator
    {

        public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(System.Type type, Ninject.Syntax.IBindingRoot bindingRoot)
        {
            if (type.IsInterface || type.IsAbstract)
                yield break;

            yield return bindingRoot.Bind(type).ToProvider(typeof(UIExtensibility.AbstractAddon));
        }
    }

    private class AddonProvider : IProvider<UIExtensibility.AbstractAddon>
    {

        public object Create(IContext context)
        {
            return null;
        }

        public Type Type
        {
            get { throw new NotImplementedException(); }
        }
    }
}

AddonProvider seems be avoided. This is never performed.

When I perform: kernel.GetAll<UIExtensibility.AbstractAddon>(), AddonProvider.Create method is never performed.

Could you tell me what's wrong? I'll appreciate a lot your help.

Thanks for all.

回答1:

AddOnProvider is inheriting from IProvider<T> instead of UIExtensibility.AbstractAddon.

also, you may have issues binding to private inner classes. make AddOnProvider a public top level class.



回答2:

You're binding a specific type which inherits from typeof(UIExtensibility.AbstractAddon) to a provider. For example, there could be a class Foo : UIExtensibility.AbstractAddon. Now your convention binding translates to this:

Bind<Foo>().ToProvider<AddonProvider>();

Now, kernel.GetAll<UIExtensibility.AbstractAddon>() however is looking for bindings made like:

Bind<UIExtensibility.AbstractAddon>().To...

Fix It

So what you need to do is change the line

bindingRoot.Bind(type).ToProvider(new AddonProvider());

to:

bindingRoot.Bind(typeof(UIExtensibility.AbstractAddon)).ToProvider<AddonProvider>();

Furthermore

  • you're line object f = bindingRoot.Bind(type).ToProvider(new AddonProvider()); is never returning the binding (object f).
  • does UIExtensibility.AbstractAddon implement IProvider?


回答3:

Thanks for your answer and comments.

I believe the trouble is on I'm not quite figuring out how this "generic" binding process works.

I'm going to try writing my brain steps process out:

  1. I need to bind every AbstractAddon implementation inside addons assemblies folder. So, I think this code is right, but I'm not sure at all.

    this.Bind(b => b.FromAssembliesMatching("*")
        .SelectAllClasses()
        .InheritedFrom(typeof(UIExtensibility.AbstractAddon))
        .BindWith(new AddonBindingGenerator())
    );
    
  2. My AbstractAddon is like:

    public abstract class AbstractAddon : IAddon
    {
    
        private object configuration;
    
        public AbstractAddon(object configuration)
        {
            this.configuration = configuration;
        }
    
        // IAddon interface
    
        public abstract string PluginId { get; }
    
        public abstract string PluginVersion { get; }
    
        public abstract string getCaption(string key);
    
        public abstract Type getConfigurationPanelType();
    
        public abstract System.Windows.Forms.UserControl createConfigurationPanel();
    
    }
    
  3. I guess I need to:

    foreach implementation of `AbstractAddon` found out,
        I need to "inject" a configuration object ->
            So, I guess I need to set a provider and provide this configuration object.
    

This would be my main way of thinking in order to solve this problem.

I've changed a bit my first approach. Instead of using a IBindingGenerator class, I've used the next:

    public class AddonsModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            this.Bind(b => b.FromAssembliesMatching("*")
                .SelectAllClasses()
                .InheritedFrom(typeof(UIExtensibility.AbstractAddon))
                .BindAllBaseClasses()
                .Configure(c => c.InSingletonScope())
            );

            this.Bind<object>().ToProvider<ConfigurationProvider>()
                .WhenTargetHas<UIExtensibility.ConfigurationAttribute>();
        }

So, My ConfigurationProvider is:

private class ConfigurationProvider : IProvider<object>
{

    public object Create(IContext context)
    {
        return "configuration settings";
    }
}

And now, my AbstractAddon constructor contains the parameter annotated with ConfigurationAttribute as:

public AbstractAddon([Configuration]object configuration)
{
    this.configuration = configuration;
}

The problem now, NInject seems to ignore the configuration object provider. NInject generates a dump object, however, not perform ConfigurationProvider.Create method...

What I'm doing wrong, now? Is this approach really better than the last one? Thanks for all.



标签: ninject