Ninject.Extensions.Conventions provides convention based binding for Ninject modeled after the StructureMap 2.5 AssemblyScanner by Jeremy Miller.
When StructureMap users can use something like:
Scan(scanner =>
{
scanner.AssembliesFromApplicationBaseDirectory(assembly => assembly.FullName.StartsWith("Ntk.Infrastructure."));
scanner.ConnectImplementationsToTypesClosing(typeof (IMessageHandler <,>));
scanner.ConnectImplementationsToTypesClosing(typeof (IMessageHandler <>));
});
Ninject.Extensions.Conventions using GenericBindingGenerator can not:
kernel.Scan(scanner =>
{
scanner.FromAssembliesMatching( "Ntk.Infrastructure.*.dll" );
scanner.BindWith(new GenericBindingGenerator(typeof(IMessageHandler<>)));
scanner.BindWith(new GenericBindingGenerator(typeof(IMessageHandler<,>)));
scanner.InTransientScope();
});
So slightly modified version of GenericBindingGenerator called MultipleGenericBindingGenerator comes to the rescue:
kernel.Scan(scanner =>
{
scanner.FromAssembliesMatching("Ntk.Infrastructure.*.dll");
scanner.BindWith(new MultipleGenericBindingGenerator(typeof(IMessageHandler<>),typeof(IMessageHandler<,>)));
scanner.InTransientScope();
});
If anyone needs anything like this, here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Ninject;
using Ninject.Activation;
using Ninject.Extensions.Conventions;
namespace TestProj{
public class MultipleGenericBindingGenerator : IBindingGenerator
{
private static readonly Type TypeOfObject = typeof (object);
private readonly Type[] _contractTypes;
/// <summary>
/// Initializes a new instance of the <see cref="MultipleGenericBindingGenerator"/> class.
/// </summary>
/// <param name="contractTypes">Types of the contract.</param>
public MultipleGenericBindingGenerator(params Type[] contractTypes)
{
foreach (var type in contractTypes)
{
if (!(type.IsGenericType || type.ContainsGenericParameters))
{
throw new ArgumentException(String.Format("The contract must be an open generic type ({0}).",type.Name), "contractTypes");
}
}
_contractTypes = contractTypes;
}
#region Implementation of IBindingGenerator
/// <summary>
/// Processes the specified type creating kernel bindings.
/// </summary>
/// <param name="type">The type to process.</param>
/// <param name="scopeCallback">the scope callback.</param>
/// <param name="kernel">The kernel to configure.</param>
public void Process( Type type, Func<IContext, object> scopeCallback, IKernel kernel )
{
Type interfaceType = ResolveClosingInterface( type );
if ( interfaceType != null )
{
kernel.Bind( interfaceType ).To( type ).InScope( scopeCallback );
}
}
#endregion
/// <summary>
/// Resolves the closing interface.
/// </summary>
/// <param name="targetType">Type of the target.</param>
/// <returns></returns>
public Type ResolveClosingInterface( Type targetType )
{
if ( targetType.IsInterface || targetType.IsAbstract )
{
return null;
}
do
{
Type[] interfaces = targetType.GetInterfaces();
foreach ( Type @interface in interfaces )
{
if ( !@interface.IsGenericType )
{
continue;
}
if (_contractTypes.Contains(@interface.GetGenericTypeDefinition()))
{
return @interface;
}
}
targetType = targetType.BaseType;
} while ( targetType != TypeOfObject );
return null;
}
}
}
27919a4f-f7fb-49c9-bad0-a0816fe43084|14|5.0