 Wednesday, April 18, 2007
So I've decided to do a quick little series on the windsor container - all up It'll probably cover 15 to 20 posts... each one should be very short, covering some small concept... just a little nugget.
This series will be a little different then most discussions on IoC and containers... rather then get in your face with concepts like dependency injection, and encouraging testability, it's just going to focus on the container itself, and the ways you can use it... I'm not sure if it'll be of any value, but If nothing else to gets me back into blogging regularly.
The first 7 parts are already up:
I'll be posting them in batches... so the series should be finished within a week.
 Tuesday, April 17, 2007
 So this time we're going to look at how you can not only change configuration for a component at runtime, but actually change which component is doing the work for us... powerful stuff :) So the "trick" here is to abstract out what features we expect our component to support from it's implementation, and stuff those into an interface... so in this case I have an idea for a simple service which lets us get the "message of the day" - so lets look at my interface:
public interface IMessageOfTheDay
{
string GetMessageOfTheDay();
} Now we have two implementations of this service, one that lets us have a static message set via configuration:
public class StaticMessageOfTheDay : IMessageOfTheDay
{
private string _message;
public string Message
{
set { _message = value; }
}
public string GetMessageOfTheDay()
{
return _message;
}
} And another, which goes to wiki quotes and grabs the quote of the day:
public class WikiQuotesMessageOfTheDay : IMessageOfTheDay
{
public string GetMessageOfTheDay()
{
WebClient client = new WebClient();
string content = client.DownloadString("http://en.wikiquote.org/wiki/Main_Page");
string toFind = "<div style=\"background: #fff5f5\">";
int start = content.IndexOf(toFind) + toFind.Length;
int length = content.IndexOf("<a", start) - start;
return content.Substring(start, length);
}
} so - our program is pretty simple:
private static void Main(string[] args)
{
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
IMessageOfTheDay motd = container.Resolve<IMessageOfTheDay>();
Console.WriteLine("MOTD: {0}", motd.GetMessageOfTheDay());
Console.Read();
}
And so how do we swap between implementations, well we need to introduce an additional attribute to our components configuration called "service" where we specifiy what service our component implements... in this case it will be "IMessageOfTheDay" - so heres the configuration when using the Static MOTD class:
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="motd.service"
service="IoC.Tutorials.Part7.IMessageOfTheDay, IoC.Tutorials.Part7"
type="IoC.Tutorials.Part7.StaticMessageOfTheDay, IoC.Tutorials.Part7">
<parameters>
<message>Welcome to my container tutorials</message>
</parameters>
</component>
</components>
</castle>
</configuration> And running the program gives us: MOTD: Welcome to my container tutorialsBut we can now swap to a different component with the same service at run-time, and get a different implementation... here's how that looks:
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="motd.service"
service="IoC.Tutorials.Part7.IMessageOfTheDay, IoC.Tutorials.Part7"
type="IoC.Tutorials.Part7.WikiQuotesMessageOfTheDay, IoC.Tutorials.Part7" />
</components>
</castle>
</configuration> And now running the program gives us: MOTD: Man is not an end but a beginning. We are at the beginning of the second week. We are children of the eighth day.A quote from Thorton Wilder - exciting huh, this seperation between interface and implementation is what makes doing so many cool things with an Inversion of control container possible... soak up the idea. Next time we'll take a look at getting different implementations by using their "key" - have you been wondering what the "id" attribute is for in our component definitions?? Well wonder no more.
 Switching lifestyles is the theme of this post... so what's that all about? Well first off - what is a lifestyle, in basic terms it specifies how many instances will be available at any one time from the container - so at the one extreme we have components with a transient lifestyle, where any requests from those components will return new instances - and at the opposite end of the spectrum we have singleton components, where there is only one instance for the whole container - there are other types of lifestyle, but we'll leave those for another post. So first off - castle is all about convention over configuration, and by convention a component in the container is a singleton... so in this example we'll look into ways in which you can switch a components lifestyle to being transient. First off, heres our component:
public class AddingService
{
private int _total = 0;
public void AddAmmount(int ammount)
{
_total += ammount;
}
public int Total
{
get { return _total; }
}
} It lets us add stuff... how neat is that... lets see our program:
private static void Main(string[] args)
{
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
AddingService sheepCounted = container.Resolve<AddingService>();
AddingService catsHerded = container.Resolve<AddingService>();
sheepCounted.AddAmmount(10);
sheepCounted.AddAmmount(50);
catsHerded.AddAmmount(3);
catsHerded.AddAmmount(12);
Console.WriteLine("You have counted {0} sheep and herded {1} angry cats", sheepCounted.Total,
catsHerded.Total);
Console.Read();
} And if we run it: You have counted 75 sheep and herded 75 angry catsThat doesn't seem right - our service is retaining a count, so we want a fresh instance of the class every time we request it - which means we should shift our component to the "transient" lifestyle - lets have a go at doing it with configuration, by adding the lifestyle attribute to the components definition.
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="adding.service" type="IoC.Tutorials.Part6.AddingService, IoC.Tutorials.Part6" lifestyle="transient" />
</components>
</castle>
</configuration> And now if we run it again: You have counted 60 sheep and herded 15 angry catsThat looks a bit better... but I propose that in many cases when your writing a component you know what it's lifestyle should be, before it's ever registered in a container - for instance in this case this class should always be transient, so we can actually decorate the class with a "Transient" attribute and can skip having to put the lifestyle in the configuration, this is how that would look:
[Transient]
public class AddingService
{
private int _total = 0;
public void AddAmmount(int ammount)
{
_total += ammount;
}
public int Total
{
get { return _total; }
}
} There are other lifestyles available to use - it's worth having a look through the castle wiki for more details... and we'll probably cover them in another post. In the next part we will cover switching out implementations of components themselves.
 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
<configuration>
<properties>
<configName>Debug</configName>
</properties>
</configuration> properties-live.config
<configuration>
<properties>
<configName>Live</configName>
</properties>
</configuration> And now the app.config...
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<include uri="file://properties-debug.config" />
<!--<include uri="file://properties-live.config" />-->
<component id="whatConfig.service" type="IoC.Tutorials.Part5.WhatConfigurationService, IoC.Tutorials.Part5">
<parameters>
<Configuration>#{configName}</Configuration>
</parameters>
</component>
</components>
</castle>
</configuration> 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 <include/> 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).
 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<WhatConfigurationService>();
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
<configuration>
<components>
<component id="whatConfig.service" type="IoC.Tutorials.Part4.WhatConfigurationService, IoC.Tutorials.Part4">
<parameters>
<Configuration>Debug</Configuration>
</parameters>
</component>
</components>
</configuration> container-live.config
<configuration>
<components>
<component id="whatConfig.service" type="IoC.Tutorials.Part4.WhatConfigurationService, IoC.Tutorials.Part4">
<parameters>
<Configuration>Live</Configuration>
</parameters>
</component>
</components>
</configuration> 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:
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<!--<include uri="file://container-debug.config" />-->
<include uri="file://container-live.config" />
</castle>
</configuration> 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: LiveThere 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.
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<string, string> _aliases;
public Dictionary<string, string> 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<AliasService>();
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 homeworkHmm... I'm not sure that's a great excuse for late delivery... let's do some configuration and try again:
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="aliases.service" type="IoC.Tutorials.Part3.AliasService, IoC.Tutorials.Part3">
<parameters>
<Aliases>
<dictionary>
<entry key="dog">duck</entry>
<entry key="ate">broke</entry>
<entry key="homework">code</entry>
</dictionary>
</Aliases>
</parameters>
</component>
</components>
</castle>
</configuration> 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.
 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 goto 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<HolidayService>();
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...
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="holidays.service" type="IoC.Tutorials.Part2.HolidayService, IoC.Tutorials.Part2" >
<parameters>
<Holidays>
<array>
<item>2007-12-24</item>
<item>2007-12-25</item>
<item>2008-1-1</item>
</array>
</Holidays>
</parameters>
</component>
</components>
</castle>
</configuration> 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.
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<TaxCalculator>();
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:
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="taxcalc.service" type="IoC.Tutorials.Part1.TaxCalculator, IoC.Tutorials.Part1" />
</components>
</castle>
</configuration> Running the program will display: Gross: 100, Tax: 12.50Now, what about changing the tax rate in the configuration?
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="taxcalc.service" type="IoC.Tutorials.Part1.TaxCalculator, IoC.Tutorials.Part1">
<parameters>
<Rate>0.25</Rate>
</parameters>
</component>
</components>
</castle>
</configuration>
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...
 Sunday, April 15, 2007
Well it’s over – and it’s been great!
First off Architecture Camp 2007 was a lot of fun to present
at this weekend... the relaxed nature and opportunities for everyone to talk, rather than
just listening, was great – a nice soft introduction to a newbie presenter such
as myself!
And a big hat-tip to all the guys who helped put this
together, including Alex James, Kurt (where’s your blog boy!) and Chris + all the
other presenters.
The thing I liked the most about this event was the number of
people who brought their a-game... damn but there were some seriously
experienced and intelligent guys in the audience, asking great questions – contrasted with the often
pointless heckling and misguided questioning you can get at events like teched,
this event was great ... if you couldn’t make it, definitely try to get to the
next architecture camp, and if you were a no-show ... shame on you!
I’m still not 100% sure if my session got recorded or not,
but if it did, I’ll point you to it at some point... in the mean time – here’s the presentation
itself in both pdf and pptx (powerpoint 2007) formats.
 Thursday, March 29, 2007
In a follow up to this post I made yesterday, it seems some people are annoyed that a Codeplex command line client exists at all... I still can not help but feel some people are missing the point of Codeplex all together... as I see it (and these are only my opinions on the matter) - Codeplex: - Supersedes the aging gotdotnet.
- Demonstrates TFS features
- Scalability for high volumes of users (not necessarily usability, but they're working on that)
- Case study for any large organizations considering deploying it across their organization.
- Provides a place Microsoft can.
- Host open-source projects for life.
- Control and support the environment.
- Keep a single message across their organization - we use TFS for source control from now on.
(At this point it's worth noting I'm a SVN/Trac/CC.Net guy myself... I can't actually justify the expenses of TFS at the moment)For me the reasons to use codeplex over another open source provider are simply: - It's different / new.
- It has a strong Microsoft / .Net focus.
- It's easier to get going for a newbie .Net developer (integrated source control in VS.Net, simple wiki pages baked-in)
- You can play with TFS.
They are reasons, but hardly "compelling" ones ;o) The beta command line client is a good thing, but to counter that "6 months wasted effort" with a call to replace TFS with subversion in Codeplex ... that just seems counter-intuitive to me... suddenly you have a roll-on effect of zero integration between source control and the in-built issue tracking mechanisms... so what, lets replace that with Trac??... and now that comes with it's own wiki... so ditch the existing one... and suddenly Codeplex is nothing more then a shell for managing file releases with some forums. What kind of message would it send to microsoft customers who have invested time and effort into team system... let's be reasonable, it's just not going to happen, so whats the next logical step... improve the tooling to work with the existing source control solution... first step to achieving that... build a decent command line client! So... if you are looking for subversion based hosting why not use well established players who have been supporting open source from the beginning like SourceForge or tigris... don't they still deserve your love now more then ever since Codeplex is on the scene... what better way to vote than with your choice of OSS project hosting? Codeplex is an alternative, not a replacement, for the likes of Sourceforge... perhaps what we need is a OssHostMatrix, much like WikiMatrix that compares feature for feature so you can pick the host that's appropriate to your project on features alone, rather then bitching about what's missing in Codeplex, when it's freely available elsewhere... I'm starting to feel sorry for some of the codeplex guys (like Jonathan Wanagel, who I commend for being vocal about what's going on at codeplex... he seems to pop up on a lot of blogs I read) ... they certainly do seem a little damned if you, damned if you don't at the moment - especially when progress is slowly being made and demonstrated.
© Copyright 2008 Alex Henderson
Theme design by Bryan Bell
newtelligence dasBlog 1.9.6264.0  | Page rendered at Wednesday, August 20, 2008 7:05:47 AM (New Zealand Standard Time, UTC+12:00)
|
Search
FeedCount
Tags...
Who am I?

|
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited
"Self Confessed Coding Junky for 15 years"
|
 |
| |
| Mobile: |
+64-21-402-969 |
| Email: |
bittercoder 'at' gmail 'dot' com |
| MSN: |
bittercoder_nz@hotmail |
| Skype: |
alex.devdefined |
Navigation
|