A Replacement for Ninject’s WithConstructorArgument Method

When defining DI bindings with Ninject’s fluent syntax one may specify values for constructor arguments of a given type. Supposing that we have a ThingImpl type that has a string argument named prefix, we can write:

kernel.Bind<IThing>()
      .To<ThingImpl>()
      .WithConstructorArgument("prefix", "[TEST]");

You can assign values for different arguments by invoking WithConstructorArgument multiple times. If there’s an error on the argument names or types it will only be caught when there is a request for the service (IThing in this case). Also, Ninject will report that it couldn’t find a binding for some argument, instead of reporting that you’re using a wrong argument name.

Another possible approach is a method that allows you to specify all the arguments (using an anonymous type) and checks if the type’s constructors have matching arguments.

kernel.Bind<IThing>()
      .To<ThingImpl>()
      .WithConstructorArguments(new { prefix = "[PRE]", date = DateTime.UtcNow});

This method can be easily implemented using some reflection goodness:

    public static class BindingWithSyntaxExtensions
    {
        public static IBindingWithOrOnSyntax<T> WithConstructorArguments<T>(
            this IBindingWithSyntax<T> syntax,
            object constructorArguments)
        {
            var args = constructorArguments.GetType().GetProperties();
            if(args.Length == 0)
            {
                throw new ArgumentException("No public properties", "constructorArguments");
            }

            foreach(var prop in args)
            {
                if (typeof(T).GetConstructors()
                    .Any(c => c.GetParameters()
                        .Any(p => p.ParameterType.IsAssignableFrom(prop.PropertyType) && p.Name == prop.Name)))
                {
                    syntax = syntax.WithConstructorArgument(prop.Name, prop.GetValue(constructorArguments, null));
                }
                else
                {
                    throw new InvalidOperationException(String.Format("Constructor argument '{0}' ({1}) not found on {2}", prop.Name, prop.PropertyType, typeof(T).FullName));
                }
            }

            return (IBindingWithOrOnSyntax<T>)syntax;
        }
    }

This will provider feedback when configuring the bindings and alert you if you’re using names/types that don’t match the ones on the type’s constructors.

Advertisements

2 thoughts on “A Replacement for Ninject’s WithConstructorArgument Method

  1. Nice article — I tried to implement this, but the extension signature seems to match an existing method signature for WithConstructorArguments already included in Ninject (maybe they added it since your post, but there doesn’t seem to be compile-time error checking like your implementation). Have you found a way around this?

    • You probably mean the WithConstructorArgument(TValue v) overload. I didn’t notice that. You probably could rename my implementations to be plural (WithConstructorArguments) since it allows to specify multiple arguments on the same invocation.

      Anyway, you can also try binding using ToConstructor, which allows to specify which parameters should be injected and which are constants.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s