How do I use the Ninject Conventions library to bi

2019-05-07 03:47发布

I'm trying to scan for a set of components that implement a specific base class in the assemblies in the same directory as my application. I need to do this as a sort of plugin-style architecture, as my application uses these types to populate other components.

Ninject.Extensions.Conventions supports scanning assemblies in the local directory, so I decided to give it a shot.

The problem is that the binding generators that library provides (DefaultBindingGenerator and RegexBindingGenerator) will only bind components to interfaces that they implement. They won't bind to non-interface base types.

How do I use this library to bind by convention to a base class, rather than an interface?

I am using the version currently on NuGet - 2.2.0.5

My current convention-based binding code looks like this:

Kernel.Scan(x =>
{
    x.FromAssembliesMatching("*.dll");
    x.WhereTypeInheritsFrom<BaseType>();

    // I've tried both DefaultBindingGenerator and RegexBindingGenerator
    x.BindWith<DefaultBindingGenerator>();

    x.InTransientScope();
});

When I try to resolve the components, nothing is returned:

var myTypes = Kernel.GetAll<BaseType>();
int count = myTypes.Count(); // Always returns zero

2条回答
疯言疯语
2楼-- · 2019-05-07 04:06

In the current code base up on GitHub, you can use the BaseBindingGenerator.

In the codebase I have (the one currently on NuGet - 2.2.0.5), I solved this using a custom IBindingGenerator. It was fairly simple to write once I looked at the sources for the existing binding generators.

public class BaseTypeBindingGenerator<TBase> : IBindingGenerator
{
    private static readonly Type baseType = typeof(TBase);

    public void Process( Type type, Func<IContext, object> scopeCallback,
        IKernel kernel )
    {
        if ( type.IsInterface || type.IsAbstract || type.BaseType != baseType)
        {
            return;
        }

        kernel.Bind(baseType).To(type).InScope(scopeCallback);
    }
}

I used it like this:

Kernel.Scan(x =>
{
    x.FromAssembliesMatching("*.dll");
    x.WhereTypeInheritsFrom<BaseType>();

    x.BindWith<BaseTypeBindingGenerator<BaseType>>();

    x.InTransientScope();
});

// ...

var myTypes = Kernel.GetAll<BaseType>();
int count = myTypes.Count(); // Didn't return zero!
查看更多
我命由我不由天
3楼-- · 2019-05-07 04:21

Just an update on Merlyn´s answer, I am using ninject extensions conventions 3.2, and the signature has changed a little bit...

public class BaseTypeBindingGenerator<TBase> : IBindingGenerator
{
    private static readonly Type baseType = typeof (TBase);

    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        if (type.IsInterface || type.IsAbstract || type.BaseType != baseType)
        {
            return Enumerable.Empty<IBindingWhenInNamedWithOrOnSyntax<object>>();
        }

        return new [] { bindingRoot.Bind(baseType).To(type) };
    }
}
查看更多
登录 后发表回答