Part 9 - Constructor Injection

9_constructor_injection.png



Constructor injection - so far inadvertantly we've been using setter inject to get our configuration information into our components... but you can also use constructors... the useful aspect of constructors is that it makes those parameters compulsory...



So lets take a look at the code for this post, first off there's an interface for a service which takes care of encoding a string for us:


public interface IEncoder
{
string Encode(string source);
}


And then we have no classes which implement this service, one we can use when testing to not encode things at all - and another which encodes a string using our particularly strong "silly" encryption...



NullEncoder.cs

public class NullEncoder : IEncoder
{
public string Encode(string source)
{
return source;
}
}


SillyEncoder.cs


public class SillyEncoder : IEncoder
{
private char[] _mixedUp = "YACBDFEGIHJLKMONPRSQTUWVXZ".ToCharArray();

public string Encode(string source)
{
string upperSource = source.ToUpper();
char[] encoded = new char[source.Length];
for (int i = 0; i < encoded.length;="">
{
encoded[i] = MapCharacter(upperSource[i]);
}
return new string(encoded);
}

private char MapCharacter(char ch)
{
if ((ch >= 'A') && (ch <=>
{
return _mixedUp[ch - 'A'];
}
return ch;
}
}



When then have a class for sending messages (currently we just send it to the console, so we can print them out and paste them onto the back of postcards) ... so lets have a look at that class:


public class SecretMessageSender
{
private readonly IEncoder _encoder;
private readonly string _from;

public SecretMessageSender(string from, IEncoder encoder)
{
_from = from;
_encoder = encoder;
}

public void SendMessage(string to, string body)
{
Console.WriteLine("to: {0}rnfrom: {1}rnrn{2}", to, _from, _encoder.Encode(body));
}
}



Notice the lack of default constructor, and that the constructor also takes an instance of type IEncoder... now Castle is smart enough to do two things for us:
  • Throw an exception if we try to get an isntance of SecreteMessageSender without having set the from configuration parameter.
  • Find the default implementation of the IEncoder registered in the container, and to supply that as the value for the second argument in the constructor.

So lets have a look at the application itself:


static void Main(string[] args)
{
WindsorContainer container = new WindsorContainer(new XmlInterpreter());

SecretMessageSender sender = container.Resolve();

sender.SendMessage("hammet", "castle is great!");

Console.Read();
}



And finally our configuration:




type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />




service="IoC.Tutorials.Part9.IEncoder, IoC.Tutorials.Part9"
type="IoC.Tutorials.Part9.SillyEncoder, IoC.Tutorials.Part9" />


service="IoC.Tutorials.Part9.IEncoder, IoC.Tutorials.Part9"
type="IoC.Tutorials.Part9.NullEncoder, IoC.Tutorials.Part9" />


type="IoC.Tutorials.Part9.SecretMessageSender, IoC.Tutorials.Part9">

SecretMessageSender
alex@bittercoder.com





So you can see we've registered both implementations of the encoder, with the silly encoder being first - so as mentioned in the last part - this will be the default - and we also register our message sender (with the required from parameter)... so what happens when we run it:



to: hammet

from: alex@bittercoder.com



CYSQLD IS ERDYQ!




Cool... but what if wanted to send an unencrypted message... well we have a few options:
  • Swap the order in which the implementations are registered
  • Remove / comment out any implementations we don't want (so comment out the silly encoder)
  • Or reference the implementation we specifically want to wire up to, using it's identifier...

So lets have a look at the last one...




type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />




service="IoC.Tutorials.Part9.IEncoder, IoC.Tutorials.Part9"
type="IoC.Tutorials.Part9.SillyEncoder, IoC.Tutorials.Part9" />


service="IoC.Tutorials.Part9.IEncoder, IoC.Tutorials.Part9"
type="IoC.Tutorials.Part9.NullEncoder, IoC.Tutorials.Part9" />


type="IoC.Tutorials.Part9.SecretMessageSender, IoC.Tutorials.Part9">

SecretMessageSender
alex@bittercoder.com
${encoder.null}





Notice the way the parameter is formatted - instead of the markup for a property reference which starts with a hash (#) we start service references with a dollar sign ($) and then surround the components identifier with braces.



And the results of running the app now:



to: hammet

from: alex@bittercoder.com



castle is great!



And thats our first look at constructor injection... we will revisit constructor injection again in later posts, however the next part will look at setter injection.
Written on April 19, 2007