Settings Objects

Configurability is a member of the *-ability gang. Influence how your components work at runtime. Store configuration information somewhere. Either in code, in a config file or in some type of database. Load it at runtime and use it in your application.

You can hard-code the way these values are retrieved directly in your components. But that makes these components hard to test and limits your flexibility (another gang-member) later in the process. You can hand them to your component one-by-one either as constructor parameters or method parameters which tends to get very noisy if you need more than a few values. The Parameter Object Refactoring can reduce that noise a lot. Yet it does not solve the problem of how to get the values into that parameter object.

You can use some custom ConfigurationManager or extend the .NET configuration engine. But what about defining defaults for your configuration? Defaults for different scenarios maybe? Meaningful defaults can greatly reduce the clutter in your configuration.

I found another approach very useful: Encapsulate the way your configuration values are retrieved along with the defaults into something I call Settings Objects.

They contain a number of public virtual properties that are used to retrieve the desired configuration values.

public class DemoSettings
{
  private static class Defaults
  {
    public static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);
  }
  public virtual TimeSpan Timeout
  {
    get
    {
      string key = GetKeyFor(() => Timeout);
      string valueFromConfigFile = ConfigurationManager.AppSettings[key];
      TimeSpan ts;
      if (!string.IsNullOrEmpty(valueFromConfigFile) &&
          TimeSpan.TryParse(valueFromConfigFile, CultureInfo.CurrentCulture, out ts))
      {
        return ts;
      }
      return Defaults.Timeout;
    }
  }
  private string GetKeyFor(Expression<Func> memberSelector)
  {
    MemberExpression expression = (MemberExpression) memberSelector.Body;
    string key = this.GetType().Name + "." + expression.Member.Name;
    return key;
  }
}

The code in this demo tries to load configuration values from a config file following an easy convention: Values are stored as <NameOfTheSettingsClass>.<PropertyName> in the appSettings section.

If no value is found or the value does not meet the format expectations a hard-coded default is used. If performance is critical you can use a private member or any kind of cache to store the retrieved value. You can implement expiration for your cached values if you want to.

If you derive from DemoSettings you can use different default values in your derived classes. Or you can entirely hard-code values. Which is especially useful for testing scenarios. Or you can turn that procedure upside-down and design a base-class that uses hard-coded values (e.g. in the beginning of the development of a new component) and derive settings objects with different methods for information retrieval later as needed.

You can read from a database instead of a config file. Or you can implement a “three strikes” scenario: Check wether the value is defined in your local config file. If not check the database. If there is no value in the database use the default. By this, values in a config file override values in a database which in turn override the hard-coded defaults.

Btw.: If you are using a database caching might make sense to avoid too many round-trips. And if you are already on .NET 4.5 you can use the CallerMemberNameAttribute instead of an Expression to figure out the name of the property you want to retrieve.

You can argue that Settings Objects violate the Single Responsibility Principle and I agree with you. A settings DTO and a separate Loader class of some kind are more SRP’ish. But in this case I value the improved useability of settings objects more than following SRP. They are small, self-contained objects. If you don’t need the additional configurability stick with hard-coded values. That minimizes the effort until you really have a need for that flexibility (and someone is willing to pay you for it). You don’t have to write another “framework” to fill your settings objects with values from various sources. You can decide on a case-by-case basis wether you need support for config-files or databases or something else or if hard-coded values are good enough for now. I like this approach and it served me well on several projects.

Advertisements

Fun with constructor arguments Part 2.1: Anonymous overrides revisited

After publishing the post on Anonymous overrides I thought about the topic again. In the end it didn’t make sense to put that functionality in a separate class.

The SmartConstructor already does most of the heavy lifting and matching the properties of an anonymous object to constructor parameters can easily be encapsulated in a new ParameterMatchingConvention.

As a result the SmartConstructor grew by a few lines of code (reading the properties of the anonymous object and converting them to ConstructorParameters) and I created a new convention called StringAsMappingNameMatchingConvention.

Get the overhauled source code for the SmartConstructor here (project TecX.Unity folder Injection and the test suite that shows how to use it in TecX.Unity.Test).

Fun with constructor arguments Part 3: Named registrations

A while ago there was a question on StackOverflow: If I have multiple implementations of an interface registered as named mappings and a constructor that should consume such a named mapping how can I tell Unity to automatically match the argument name to the mapping name?

E.g. if you have the following class definitions:

public interface ICommand { }

public class LoadCommand : ICommand { }

public class SaveCommand : ICommand { }

public class Consumer
{
  public Consumer(ICommand loadCommand, ICommand saveCommand)
  {
    // ...
  }
}

Now you setup your container and register both command implementations:

container.RegisterType<ICommand, LoadCommand>("loadCommand");
container.RegisterType<ICommand, SaveCommand>("saveCommand");

And when you resolve the Consumer the LoadCommand should be used for the parameter named loadCommand and the SaveCommand should be used for the parameter named saveCommand.

This is what you would have to do using Unity as is:

container.RegisterType<Consumer>(  new InjectionConstructor(
  new ResolvedParameter(typeof(ICommand), "loadCommand"),
  new ResolvedParameter(typeof(ICommand), "saveCommand")));

And this is a “slightly” enhanced version:

container.RegisterType<Consumer>(new MapParameterNamesToRegistrationNames());

The class MapParameterNamesToRegistrationNames is derived from InjectionMember. It places a marker policy in Unity’s build pipeline. When an object is resolved by the container a custom BuilderStrategy looks for that marker. If the marker is found the strategy will replace the dependency resolvers (implementations of IDependencyResolverPolicy) that Unity puts into the pipeline by default with NamedTypeDependencyResolvers using the name of the constructor argument as name of the mapping.

public class MapParameterNamesToRegistrationNamesStrategy : BuilderStrategy
{
  public override void PreBuildUp(IBuilderContext context)
  {
    if (context.Policies.Get(
      context.BuildKey) == null)
    {
      return;
    }
    IPolicyList resolverPolicyDestination;
    IConstructorSelectorPolicy selector =
      context.Policies.Get(
        context.BuildKey, out resolverPolicyDestination);
    if (selector == null)
    {
      return;
    }
    var selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination);
    if (selectedConstructor == null)
    {
      return;
    }
    ParameterInfo[] parameters = selectedConstructor.Constructor.GetParameters();
    string[] parameterKeys = selectedConstructor.GetParameterKeys();
    for (int i = 0; i < parameters.Length; i++)
    {
      Type parameterType = parameters[i].ParameterType;
      if (parameterType.IsAbstract ||
          parameterType.IsInterface ||
          (parameterType.IsClass && parameterType != typeof(string)))
      {
        IDependencyResolverPolicy resolverPolicy =
          new NamedTypeDependencyResolverPolicy(parameterType, parameters[i].Name);
        context.Policies.Set(resolverPolicy, parameterKeys[i]);
      }
    }
    resolverPolicyDestination.Set(
      new SelectedConstructorCache(selectedConstructor), context.BuildKey);
  }
}

The registration code tells you exactly what you expect from the container. No confusing setup of InjectionConstructors and ResolvedParameters. Just another simple convention that can make your life a lot easier.

Get the source code for MapParameterNamesToRegistrationNames here (project TecX.Unity folder Injection and the test suite that shows how to use it in TecX.Unity.Test).

Fun with constructor arguments Part 1: Pick & Choose

One of Unity’s weaknesses is the verbosity of its configuration. While other containers support developers with various built-in conventions to keep the necessary setup code as compact as possible Unity requires you to state everything you want explicitely.

Consider the following skeleton of a class definition:

public class CustomerRepository
{
  public CustomerRepository(string connectionString, ILog log, ISomethingElse else) { ... }
}

Specifying the connectionString parameter for that constructor using Unity’s standard API looks like this:

container.RegisterType<ICustomerRepository, CustomerRepository>(
  new InjectionConstructor("I'mAConnectionString", typeof(ILog), typeof(ISomethingElse)));

There are a couple of things I don’t like about this approach:

  • Why do I have to write so much code to specify a single parameter?
  • Why do I have to specify all parameters although I care about only one?
  • Why does their order matter? Refactoring could break my registration code!
  • Why do I have to find out on my own that I can provide placeholders for parameters I don’t care about by providing their type?
  • Why do I have to provide those placeholders at all?

It’s all about verbosity. I don’t like to write unnecessary code. That is code I will have to write, test and maintain. The more effort I can save on that the better.

Conventions are a great means to not have to write code. They will get you 80% of the way most of the time at virtually no cost. And for the last 20% you can use the verbose API or define custom conventions that fit the special needs of your environment.

Providing a single parameter for the constructor of CustomerRepository can be as simple as this:

container.RegisterType<ICustomerRepository, CustomerRepository>(
  new SmartConstructor("I'mAConnectionString"));

What do you have to do to get that convenience? Not that much actually. SmartConstructor uses a couple of conventions to select a constructor from a set of candidates:

  • Only consider constructors that accept all provided parameters
  • Don’t consider constructors that have primitive parameters (like strings or integers) that are not satisfied by the provided parameters
  • If the parameter you specified is a string try to match it with parameters whose names contain connectionString, file or path.
  • Try to match specified parameters by parts of their type name. E.g. if you specified a parameter of type SomeTypeName a convention will look for parameters named someTypeName, typeName and name.
  • From the candidates that are left take the one with the most parameters (most greedy constructor).

The matching conventions are easy to write. They derive from ParameterMatchingConvention

public abstract class ParameterMatchingConvention
{
  public bool Matches(ConstructorParameter argument, ParameterInfo parameter)
  {
    ResolvedParameter rp = argument.Value as ResolvedParameter;
    Type argumentValueType = rp != null ? rp.ParameterType : argument.Value.GetType();
    if (argument.Value != null &&
        parameter.ParameterType.IsAssignableFrom(argumentValueType))
    {
      return this.MatchesCore(argument, parameter);
    }
    return false;
  }
  protected abstract bool MatchesCore(ConstructorParameter argument, ParameterInfo parameter);
}

That base class does some validation of the input values (which is omitted for brevity in the sample) and checks wether the type of the specified parameter matches the type of the parameter it is compared against. If that’s the case it hands over to the actual implementation of the convention. The ConnectionStringMatchingConvention for example looks as simple as that:

public class ConnectionStringMatchingConvention : ParameterMatchingConvention
{
  protected override bool MatchesCore(ConstructorParameter argument, ParameterInfo parameter)
  {
    if (parameter.ParameterType == typeof(string))
    {
      return parameter.Name.Contains("connectionString", StringComparison.OrdinalIgnoreCase);
    }
    return false;
  }
}

Done. To add a custom convention to the selection process you can call an extension method of IUnityContainer:

container.WithConstructorArgumentMatchingConvention(new MyCustomConvention());

Get the source code for the SmartConstructor here (project TecX.Unity folder Injection and the test suite that shows how to use it in TecX.Unity.Test).

Inject Primitive Dependencies by Convention

Mark Seemann, author of the book Dependency Injection in .NET, has a nice article about the injection of Primitive Dependencies.

From a technical perspective I find the part where he configures Castle Windsor to use his custom conventions most interesting. When I come across such a feature that exists in another DI container but is not present in Unity I try to port that feature. And I have yet to find some piece of functionality that cannot be implemented easily with a few lines of code. Adding support for parameter conventions takes about ~250 LoC. Due to the differences in their respective architecture the Unity implementation is two-part: The core part of the convention implements the custom interface IDependencyResolverConvention the part that performs the actual work implements IDependencyResolverPolicy which comes as part of the Unity infrastructure.

These are the interfaces:

public interface IDependencyResolverConvention
{
  bool CanCreateResolver(IBuilderContext context, DependencyInfo dependency);
  IDependencyResolverPolicy CreateResolver(IBuilderContext context, DependencyInfo dependency);
}

public interface IDependencyResolverPolicy : IBuilderPolicy
{
  object Resolve(IBuilderContext context);
}

Using that newly created infrastructure (and a second convention that works like the ConnectionStringConvention described in the article) you can resolve classes that look like these:

public class TakesPrimitiveParameter
{
  public int Abc { get; set; }
  public TakesPrimitiveParameter(int abc)
  {
    this.Abc = abc;
  }
}
public class TakesConnectionStringParameter
{
  public string AbcConnectionString { get; set; }
  public TakesConnectionStringParameter(string abcConnectionString)
  {
    this.AbcConnectionString = abcConnectionString;
  }
}

The integer value abc will be read from the appSettings section of your config file. The ConnectionString abc will be read from the connectionStrings section.

public class AppSettingsConvention : IDependencyResolverConvention
{
  public bool CanCreateResolver(IBuilderContext context, DependencyInfo dependency)
  {
    return dependency.DependencyType == typeof(int);
  }
  public IDependencyResolverPolicy CreateResolver(IBuilderContext context, DependencyInfo dependency)
  {
    return new AppSettingsResolverPolicy(dependency.DependencyName, dependency.DependencyType);
  }
}

public class AppSettingsResolverPolicy : IDependencyResolverPolicy
{
  private readonly string name;
  private readonly Type targetType;
  public AppSettingsResolverPolicy(string name, Type targetType)
  {
    this.name = name;
    this.targetType = targetType;
  }
  public object Resolve(IBuilderContext context)
  {
    string setting = ConfigurationManager.AppSettings[this.name];
    return Convert.ChangeType(setting, this.targetType);
  }
}

Setting up the registrations is as easy as this:

var container = new UnityContainer().WithDefaultConventionsForLiteralParameters();
var foo = container.Resolve<TakesPrimitiveParameter>();

Or if you prefer to have more fine granular control over the used conventions you can add them one by one:

var container = new UnityContainer()
                 .WithConventionsForLiteralParameters(
                   new ConnectionStringConvention(),
                   new AppSettingsConvention());
var foo = container.Resolve<TakesPrimitiveParameter>();

Neat and as Mark puts it: If you stick to your conventions it will just keep working when your code base grows.

Get the source code for the convention based injection here (project TecX.Unity folder Literals and the test suite that shows how to use it in TecX.Unity.Test).