Monday, March 9, 2009

Castle: We Still XML The Old Way

Post 4 in a 101 series on the Castle IOC project called Windsor. See part one for background

XML Config Based Registration

Although demoware may show us the inline registration of components is good it may not prove to be the best thing for your application. The previous posts have shown registration of types in C#, this means we must recompile if we are making changes to any parts of our registration. This may be considered a bad thing, it may also be considered a bad thing that the assembly that you are performing all of this registration in knows about (and has references to)  a lot of possibly inappropriate libraries and projects. One way around all of this is by using the XML configuration.

Using our same basic console app I add an app.config file and put the following in it:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component lifestyle="transient"
id="Writer"
service="CastleIocConsole.IWriter, CastleIocConsole"
type="CastleIocConsole.HelloWriter, CastleIocConsole" />
<component
id="Gday"
service="CastleIocConsole.IWriter, CastleIocConsole"
type="CastleIocConsole.GdayWriter, CastleIocConsole" />
<component
id="List"
service="CastleIocConsole.IWriter, CastleIocConsole"
type="CastleIocConsole.ListWriter, CastleIocConsole" />
<component
id="MessageService"
service="CastleIocConsole.IMessageService, CastleIocConsole"
type="CastleIocConsole.GuidMessageService, CastleIocConsole" />
</components>
</castle>
</configuration>

Several things to note:



  • You should specify the fully qualified name any time you are declaring types in XML, that is - Full.NameSpace.Type, Assembly

  • All components have an id

  • You don't need to specify a service, if the type has no interface or is the base calls you can just declare the type.

  • you can declare lifestyles (the transient lifestyle specified is not important in this example, its just there to show it can be done)


In addition to this you can specify which concrete dependencies you want, assign component properties and declare interceptors for AOP style run time inject of code blocks (more on this to come)


Using this code we could do some thing like this:


using System;
using Castle.Core.Resource;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;

namespace CastleIocConsole
{
class Program
{
static void Main(string[] args)
{
IWindsorContainer container =
new WindsorContainer(
new XmlInterpreter(
new ConfigResource("castle")));
var writer1 = container.Resolve<IWriter>();
writer1.Write();
var writer2 = container.Resolve<IWriter>("List");
writer2.Write();
Console.ReadKey();
}
}
}

which would give the output of (see previous post for component definitions):


Hello World
122eb0e3-0812-4611-a580-7cf976039a89
5a916589-f7a5-4121-9fb6-a51cf24a6f43
977ec6f9-8110-4074-b537-047f21e6a70f
a136ae03-0caf-49fb-8511-92e3f2d39446
3aa1db17-78c8-438f-84a9-91ef14753ca7

As with any XML there seems to be a few catches so here are some gotchas that may help:



  • All components need an ID

  • First in best dressed: The first component registered is the default for that service (interface)

  • Standard .net XML config notation applies eg no line breaks in definitions, generics marked up with back tick notation etc

  • There is no official XSD schema but there are user defined ones, find one and put it is  the VS schema folder eg : C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas to give you intellisense


That is the last in the 101 series for now. Soon I would like to cover



  • Interception and how you can use AOP with the Castle framework

  • Run time Config with out XML (Binsor)


Rhys


Back to Post 3

No comments: