The Contextual Binding can also be used to implement a conventions-based binding system, if you prefer conventions over declarative configuration. Many people prefer to keep infrastructure dependencies like attributes out of their code -- this can serve to keep the codebase clean, at the expense of clarity for newcomers.

For example, let's say you have two sources for configuration in your application, a LocalConfigurationSource that loads configuration information from a local file, and a RemoteConfigurationSource that loads configuration from a remote database. Services that depend on configuration information will need one or the other of these services to set up configuration. Let's say you have a consuming service that loads some of its configuration from the local source, and some from the remote source:

C#:
public class Service {
  public Service(IConfigurationSource remoteConfig, IConfigurationSource localSource) {
    //...
  }
}

In order to get Ninject to resolve these dependencies and call this constructor, you will need to declare bindings that differentiate between the two implementations of IConfigurationService. If you favor a declarative approach, you could create <nowiki>[Remote]</nowiki> and <nowiki>[Local]</nowiki> attributes, and use them to decorate the individual constructor arguments:

C#:
public class Service {
  public Service([Remote] IConfigurationSource remoteConfig, [Local] IConfigurationSource localSource) {
    //...
  }
}

Then your bindings would look like this:

C#:
Bind<IConfigurationSource>().To<RemoteConfigurationSource>().WhereTargetHas<RemoteAttribute>();
Bind<IConfigurationSource>().To<LocalConfigurationSource>().WhereTargetHas<LocalAttribute>();

However, if you'd rather not have to put the attributes in your constructor, you can rely on a conventions-based approach instead. For example, you can create a rule that says that if you want an instance of RemoteConfigurationSource, your argument has to begin with "remote", and if you want an instance of LocalConfigurationSource, it has to begin with "local". To do this, you would create bindings like this:

C#:
Bind<IConfigurationSource>().To<RemoteConfigurationSource>().Only(When.Context.Target.Name.BeginsWith("remote"));
Bind<IConfigurationSource>().To<LocalConfigurationSource>().Only(When.Context.Target.Name.BeginsWith("local"));

By using these bindings, your consuming service could have a constructor with no attributes, as shown in the first code example on this page.

Last edited Sep 13, 2009 at 3:33 AM by nkohari, version 1

Comments

No comments yet.