Part 5 - Configuration parameters

5_config_parameters.png
So in this part we're going to look at configuration parameters - parameters let you consolidate or seperate individual configuration parameters away from the components themselves, in this case we are going to create 2 config files, one for parameters to use in the live system, and the other for parameters in the debug system.

The advantage with this approach is that you don't have to duplicate the component registrations, you can leave those in one place (for the example, we just put them in the app.config)... so lets start by looking at our two sets of property configurations...

  • properties-debug.config
  • properties-live.config


properties-debug.config

      Debug
 


properties-live.config



    Live


And now the app.config...



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





#{configName}





Notice how the components configuration value has a hash (#) and some braces surrounding the word "configName" - that causes castle to look up the value of the property by the same name (which we declared in the property config file).

The application code is the same as part 4.

A common approach when working with developers who may need different configurations is to a file called say properties.config that contains all the configuration values that need to change between machines, and to not check that into source control... Be sure to also keep a "master" copy of the properties, say "master-properties.config" which provides a template for developers to create their own configuration (it's not a bad place to stick the instructions for doing this as well).

Read More

Part 4 - Switching configurations



So, we have all this stuff in a configuration file... but what if we have two sets of configuration we want to swap between - perhaps one for test and one for live... well here's one way of doing it with the Windsor container.



So this is our component, we use it for demonstrating which configuration is loaded:


public class WhatConfigurationService
{
private string _configuration;

public string Configuration
{
get { return _configuration; }
set { _configuration = value; }
}
}



Now here's the applications code:


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

WhatConfigurationService whatConfiguration = container.Resolve();

Console.WriteLine("Configuration: {0}", whatConfiguration.Configuration);

Console.Read();
}



So we do this by seperating our configuration sets into different files... so we create two configuration files, called:


  • container-debug.config
  • container-live.config

And here's what they look like:



container-debug.config



Debug






container-live.config



Live






So if we've moved configuration into seperate files, how does the container know about them.... well, we use includes... so here's our main configuration file now:




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







So you can see that to shift between the debug and live configurations we just swap between including one configuration and another...



And when live is uncommented, running the program gives us this output:



Configuration: Live




There are other ways to achieve the same thing, but this is often the easiest to understand... also take careful note of that uri attribute on the include element... you don't just have to use the file:// scheme - you can include resources (embedded in your assemblies) or extend the resource subsystem with additional support for your own types of resources - but before you do, be sure to have a look at the list of out of the box possibilities here.



One question that was asked about during Architecture Camp was how container configuration could be synchronized between multiple servers, and includes provide one possibility, because you can place your shared configuration on a network share, or implement your own special resource type, that could for instance get the configuration from a webservice.

Next time we'll look at introducing configuration parameters, which is another way to deal with the problems of having to switch between configs at runtime - and can make your configuration easier to read and maintain too.
Read More

Part 3 - Dictionary configuration

So in this part we look at creating a component which has a dictionary which gets configured... in this case we're creating a little service to handle word substitutions...



So lets have a look at the service:



public class AliasService
{
private Dictionary _aliases;

public Dictionary Aliases
{
get { return _aliases; }
set { _aliases = value; }
}

public string Evaluate(string term)
{
if (_aliases == null) return term;

while (_aliases.ContainsKey(term))
{
term = _aliases[term];
}

return term;
}
}



And the application code that uses the service:


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

AliasService aliasService = container.Resolve();

string sentence = "a dog ate my homework";

foreach (string word in sentence.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
Console.Write("{0} ", aliasService.Evaluate(word));
}

Console.Read();
}



Our component is again registered without any parameters, lets run it and see what pearls of wisdom it can share:



a dog at my homework



Hmm... I'm not sure that's a great excuse for late delivery... let's do some configuration and try again:




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





duck
broke
code








So, you can see we map keys to values via an entry key... and here's the result:



a duck broke my code


You may need to tweak the mappings, depending on what you actually broke...



Now at this point you might be wondering just how the strings are getting converted into strongly typed values for the last 3 parts - and to be honest, you won't need to know most of time, just do what "seems" right and it'll probably work... but when it doesn't, check out the castle projects wiki topic on component parameters, configuration and type converters.
Read More

Part 2 - Array Configuration



So welcome to part 2, today we're going to look at some more config - this time it's arrays...



So we have a class, that tells us when we can down tools and go to the beach...


public class HolidayService
{
private DateTime[] _holidays;

public DateTime[] Holidays
{
get
{
return _holidays;
}
set { _holidays = value; }
}

public bool IsHoliday(DateTime date)
{
if (_holidays != null)
{
DateTime matchDate = date.Date;
foreach (DateTime test in Holidays)
{
if (test.Date.Equals(matchDate))
{
return true;
}
}
}

return false;
}
}



We can set the days we are allowed off by adding dates to the holidays array...



So lets look at our code for running this service:


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

HolidayService holidayService = container.Resolve();

DateTime xmas = new DateTime(2007, 12, 25);
DateTime newYears = new DateTime(2008, 1, 1);

if (holidayService.IsHoliday(xmas))
Console.WriteLine("merry xmas!");
else
Console.WriteLine("xmas is only for management!");

if (holidayService.IsHoliday(newYears))
Console.WriteLine("happy new year");
else
Console.WriteLine("new year, you haven't done all the work for last year!");

Console.Read();
}
}



The service configuration is just like last time, we have the component registered with no parameters... so if we run the program we shall see on the screen:



xmas is only for management!

new year, you haven't done all the work for last year!


Mum will be dissapointed, she'd done a roast 'n all... so lets get some configuration in their so we can have a few days off...




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





2007-12-24
2007-12-25
2008-1-1








Now let's see if we're going to have a merry xmas and a happy new year - a quick run of our application....



merry xmas!

happy new year



You don't just have to use arrays either, you can do lists too - though I didn't show them here, just use list instead of array in the xml configuration...


See you for part 3 where we do dictionary configurations.
Read More

Part 1 - Simple configuration


Welcome to part 1... today we're looking at supporting basic configuration in components without additional coding by using the windsor container.

So - with the container we can provide configuration for a component which is loaded at runtime, so every time you start your app it will be read in - you can do this using the configuration support in .Net - but using castle makes support for this very code-light in comparison... let's take a look.



So first off, we have a class we can use to calculate the tax on a gross ammount:


public class TaxCalculator
{
private decimal _rate = 0.125m;

public decimal Rate
{
set { _rate = value; }
get { return _rate; }
}

public decimal CalculateTax(decimal gross)
{
return Math.Round(_rate*gross, 2);
}
}



By default the tax rate is 12.5% - but we can change the tax rate by setting the "Rate" property.



Now, lets look at setting up the container... so we have this code in our sample:


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

TaxCalculator calculator = container.Resolve();

decimal gross = 100;
decimal tax = calculator.CalculateTax(gross);

Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax);
Console.Read();
}



The windsor container is constructed with an "XmlInterpreter" - this configuration will pull the setup for our container from a section in the App.config.



Let's have a look at that:




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








Running the program will display: Gross: 100, Tax: 12.50



Now, what about changing the tax rate in the configuration?




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



0.25





Now running the program will display: Gross: 100, Tax: 25.00



And that's part 1 done - so now you can see how can we supply configuration parameters, and provide sensible defaults for them.

Next time we'll look at configuring arrays...

Read More