Using IronPython to configure Castle Windsor I

Castle Windsor is a very popular IoC container in the .Net world. Like almost all other containers it can be configured using either a fluent interface or an xml-based configuration file.

The fluent interface has the advantage of being strongly typed, what spares you a lot of errors caused by typos. On the other hand, it is hard coded and can’t be changed easily without recompiling (Actually you could use an IoC container to load you IoC container configuration dynamically but it give a rise to the question: “How do configure the container to load its own configuration?” ;-) )

The other option is to use an xml file. Despite being the most used solution in almost all containers it is really a very ugly solution. The configuration file can get very big and very complicated.

As I am reading IronPython in Action from Manning Publications, I thought I could configure Windsor using Python and a very tiny DSL. IronPython is an interpreted language for .Net framework. It combines the elegance of Python with the strength of .Net. Since it being interpreted it is a suitable solution for configuration.

For the beginning I will start with a simple solution, that can configure basic service without an enough for me to be able to configure just basic services without parameter zing. The syntax for configuring a simple implementation in Castle looks like:

container.AddComponent("service.name"
				typeof(IService>),
				typeof(Implementation));

Of course there is a whole bunch of other  settings like lifestyle and parameters, but I will ignore that for now.

Analyzing this one line I realized that all I need is a function with three arguments: the name of the coupling, the service type and the implementation type. SoI coded thus a function in C#:

private static void ConfigureContainer(IWindsorContainer container, string scriptPath)
{
	var engine = Python.CreateEngine();
    var runtime = engine.Runtime;
    var scope = runtime.CreateScope();
    scope.SetVariable("__main__", "__main__");
    Action<string, Type, Type> action = 
			(name, service, impl)=> 
				container.AddComponent(name, service, impl);

	//Inject this function into IronPython runtime
    scope.SetVariable("add",action); 
    var script = engine.CreateScriptSourceFromFile(scriptPath);
    var code = script.Compile();
    code.Execute(scope);
}

To test this DSL I wrote a simple interface with a single implementation to bind them with Python.

namespace PythonConfig
{
    public interface IDependency
    {
        string Name
        { get; }
    }
    public class Dependency : IDependency
    {
        public string Name
        {
            get { return "Default"; }
        }
    }
}

And the Python configuration is just as simple as

import clr
clr.AddReference("PythonConfig")
from PythonConfig import *

add("name" , IDependency, Dependency)

Now everything is ready. You can configure the container using this file:

static void Main(string[] args)
{
    var container = new WindsorContainer();
    ConfigureContainer(container, "script.py");

    var depend= container.Resolve<IDependency>();
    Console.WriteLine(depend.Name);
    Console.ReadLine();
}

And … it works as expected!

Todo’s

I am very aware that this implementation is very limited and incomplete. It is just enough for my needs (That’s how DSL ought to be). Nevertheless, I will try to add some of the missing features. In particularly following  functionalities will be considered very soon:

  • Adding a nicer API for referencing assemblies and importing namespaces.
  • Adding parameters to be passed to the constructor.
  • Referencing  already registered implementation inside the same configuration script.
  • Lifestyle management

Links

August 17, 2009 |
Tags : C# Castle DSL IoC IronPython Programming Windsor XML

About Me

Moukarram Kabbash This blog is kept alive by me, Moukarram Kabbash, a programmer, hobby photographer from Dortmund in Germany.

mouk.github.com