They've also managed to work out a way of using these attributes even when using a ContextPreservingGet by creating a fake target.
public static class NinjectTargetExtensions
{
public static T ContextPreservingGet<T>(this IContext context, Type attribute)
{
var target = new DummyTarget(typeof(T) , attribute);
var request = new Request(context, typeof(T), target, null);
var resolutions = context.GetContextPreservingResolutionRoot().Resolve(request).Cast<T>().ToList();
if (resolutions.Count == 0)
throw new ActivationException(ExceptionFormatter.CouldNotResolveBinding(request));
if (resolutions.Count > 1)
throw new ActivationException(ExceptionFormatter.CouldNotUniquelyResolveBinding(request));
return resolutions[0];
}
}
public class DummyTarget : ITarget
{
private readonly Type _targetType;
private const string _name = "DummyTarget";
private readonly DummyAttributeProvider _attributeProvider;
private readonly Future<Func<IBindingMetadata, bool>> _constraint;
private readonly DummyMethodInfo _dummyMethodInfo;
public DummyTarget(Type targetType,Type attributeType)
{
_targetType = targetType;
_dummyMethodInfo = new DummyMethodInfo(attributeType);
_attributeProvider = new DummyAttributeProvider(attributeType);
_constraint = new Future<Func<IBindingMetadata, bool>>(ReadConstraintFromTarget);
}
public object[] GetCustomAttributes(Type attributeType, bool inherit)
{
return _attributeProvider.GetCustomAttributes(attributeType, inherit);
}
public object[] GetCustomAttributes(bool inherit)
{
return _attributeProvider.GetCustomAttributes(inherit);
}
public bool IsDefined(Type attributeType, bool inherit)
{
return _attributeProvider.IsDefined(attributeType, inherit);
}
public object ResolveWithin(IContext parent)
{
if (Type.IsArray)
{
Type service = Type.GetElementType();
return GetValues(service, parent).CastSlow(service).ToArraySlow(service);
}
if (Type.IsGenericType)
{
Type gtd = Type.GetGenericTypeDefinition();
Type service = Type.GetGenericArguments()[0];
if (gtd == typeof (List<>) || gtd == typeof (IList<>) || gtd == typeof (ICollection<>))
return GetValues(service, parent).CastSlow(service).ToListSlow(service);
if (gtd == typeof (IEnumerable<>))
return GetValues(service, parent).CastSlow(service);
}
return GetValue(Type, parent);
}
protected virtual object GetValue(Type service, IContext parent)
{
var request = parent.Request.CreateChild(service, parent, this);
request.IsUnique = true;
return parent.Kernel.Resolve(request).SingleOrDefault();
}
protected virtual IEnumerable<object> GetValues(Type service, IContext parent)
{
var request = parent.Request.CreateChild(service, parent, this);
request.IsOptional = true;
return parent.Kernel.Resolve(request);
}
public Type Type
{
get { return _targetType; }
}
public string Name
{
get { return _name; }
}
public MemberInfo Member
{
get { return _dummyMethodInfo; }
}
public Func<IBindingMetadata, bool> Constraint
{
get { return _constraint; }
}
public bool IsOptional
{
get { return false; }
}
public bool HasDefaultValue
{
get { return false; }
}
public object DefaultValue
{
get { throw new NotImplementedException(); }
}
protected virtual Func<IBindingMetadata, bool> ReadConstraintFromTarget()
{
var attributes = this.GetCustomAttributes(typeof (ConstraintAttribute), true) as ConstraintAttribute[];
if (attributes == null || attributes.Length == 0)
return null;
if (attributes.Length == 1)
return attributes[0].Matches;
return metadata => attributes.All(attribute => attribute.Matches(metadata));
}
}
public class DummyMethodInfo : MethodInfo
{
private readonly Type _attributeType;
public DummyMethodInfo(Type attributeType)
{
_attributeType = attributeType;
}
public override object[] GetCustomAttributes(bool inherit)
{
throw new NotImplementedException();
}
public override bool IsDefined(Type attributeType, bool inherit)
{
throw new NotImplementedException();
}
public override ParameterInfo[] GetParameters()
{
throw new NotImplementedException();
}
public override MethodImplAttributes GetMethodImplementationFlags()
{
throw new NotImplementedException();
}
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
throw new NotImplementedException();
}
public override MethodInfo GetBaseDefinition()
{
throw new NotImplementedException();
}
public override ICustomAttributeProvider ReturnTypeCustomAttributes
{
get { throw new NotImplementedException(); }
}
public override string Name
{
get { return "ContextPreservingGet"; }
}
public override Type DeclaringType
{
get { throw new NotImplementedException(); }
}
public override Type ReflectedType
{
get { return _attributeType; }
}
public override RuntimeMethodHandle MethodHandle
{
get { throw new NotImplementedException(); }
}
public override MethodAttributes Attributes
{
get { throw new NotImplementedException(); }
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
throw new NotImplementedException();
}
}
public class DummyAttributeProvider : ICustomAttributeProvider
{
private readonly Type[] _attribs;
public DummyAttributeProvider(params Type[] attribs)
{
_attribs = attribs;
}
public object[] GetCustomAttributes(Type attributeType, bool inherit)
{
return _attribs.Where(x => x == attributeType).ToArray();
}
public object[] GetCustomAttributes(bool inherit)
{
return _attribs;
}
public bool IsDefined(Type attributeType, bool inherit)
{
return _attribs.Contains(attributeType);
}
}
It seems to work but we're interested to see if anyone else thinks this is a good solution?