Skip to content

Ninject Lives!

March 12, 2008

It’s been too quiet around here lately, so I figured I’d break the radio silence and talk about Ninject a little bit. I’ve let the project lie dormant a little too long, and a few enhancements and fixes were well past due.

The most interesting one is the addition of transient parameters. Several people have asked for the ability to pass arguments to the call to the kernel’s Get() method. I’ve always dodged the question because I felt like ordered un-typed arguments were clunky, dangerous, and difficult to implement. Being the fan I am of fluent interfaces, I came up with a solution. Bear in mind that this is a relatively advanced use for Ninject, and is only useful in edge cases.

Let’s say you have a simple DataService which provides access to a database via ADO.NET:

public class DataService {
  [Inject]
  public DataService(string connectionString) {
    …
  }
}

Up until now, you would be required to create a binding for the string type that would return the connection string. By using the new transient parameter support, you can directly specify the connection string you want to pass to the service when it is requested from the kernel:

IKernel kernel = …
DataService service = kernel.Get<DataService>(
  With.Parameters
    .ConstructorArgument(“connectionString”, “Data Source=localhost,…”)
);

When the kernel activates the DataService instance, it will pass the connection string you specify in the ConstructorArgument() call to the DataService‘s constructor. This overrides any bindings declared for string, including conditional ones. The same thing is available for properties as well. Let’s say your DataService looks like this instead (using the fancy-pants automatic properties in C# 3.0):

public class DataService {
  [Inject]
  public string ConnectionString { get; set; }
}

You could inject a value of your choice like this:

IKernel kernel = …
DataService service = kernel.Get<DataService>(
  With.Parameters
    .PropertyValue(“ConnectionString”, “Data Source=localhost,…”)
);

Note that your properties and constructors still need to be selected for injection for the transient parameters to kick in. That means that you have to mark properties with [Inject] (or whatever attribute you’ve set in KernelOptions if you’ve overridden it).

There’s also some fun stuff for setting multiple arguments at once. Say you have a simple service like this:

public class MyService {
  [Inject]
  public MyService(string foo, int bar) {
    …
  }
}

You can declare multiple transient constructor arguments with the fluent interface:

IKernel kernel = …
MyService service = kernel.Get<MyService>(
  With.Parameters
    .ConstructorArgument(“foo”, “hello”)
    .ConstructorArgument(“bar”, 42)
);

Or, you can use a dictionary:

IKernel kernel = …

Dictionary args = new Dictionary<string, object>();
args.Add(“foo”, “hello”);
args.Add(“bar”, 42);

MyService service = kernel.Get<MyService>(
  With.Parameters
    .ConstructorArguments(args)
);

Or, you can take advantage of C# 3.0 anonymous types, using a trick that’s becoming pretty popular these days. The property names of the anonymous type must correspond to the names of the constructor arguments. The value of each property will be read via reflection and injected into their corresponding argument.

IKernel kernel = …
MyService service = kernel.Get<MyService>(
  With.Parameters
    .ConstructorArguments(new { foo = “hello”, bar = 42 })
);

This same support is available for defining multiple property values at once as well. These changes are coming to the trunk sometime tonight. I’m toying with the idea of relocating the Subversion repository to Beanstalk, but I haven’t decided for sure yet. Update: The changes have been committed to the repository, and I’m going to keep it hosted with Google Code.

If you have any thoughts on the new transient parameter syntax, I’d love to hear them!

About these ads

From → miscellaneous

4 Comments
  1. I’m glad this has been implemented but it feels kind of messy, as you lose a lot of the intellisense and compile-time type checks. I’m not sure if anything could be done in this regard, though would be nice not to lose this functionality.

    Could you possibly use some kind of designer code to produce a structure for the arguments while in the IDE?

  2. Matt Howells permalink

    Dude, check out the way that Moq allows you to specify which constructor args to expect using Linq expressions – you could probably do something similar here.

  3. I do agree with Ben about the ConstructorArguments.

    You loose type checks. Change the name of a parameter in the future and you’re doomed if you don’t have integration tests.

Trackbacks & Pingbacks

  1. Ninject Release Candidate 1 at Discord&Rhyme

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: