Monthly Archives: July 2008

The Bitter Coder Tutorial, Binsor Style V – Configuration Parameters

(Sorry about the delay in the tutorials, but I took a week of vacation and my wife wouldn’t let me near the computer…)

Previous posts in the series:

In tutorial #5, Alex focuses on configuration parameters.  He creates 2 properties configuration files (live and debug) and then does an ‘include’ in the configuration XML to pull in which one he wants, commenting out the other.  I am gonna try something similar here.

Boo/Binsor allows you to include files, but there is seemingly an issue.  Any variables defined in the included file are ignored, which I found odd (scope issue?)  Anyway, I then found this post from Ayende and knew I had to get a bit creative.  My inspiration was yet another post from Ayende.  My solution was to create 2 files (live and debug, like Alex) and import them (like Alex.)   In each file is a function called DefineProperties() that returns a hash of property values.

Here is propertiesLive.boo

def DefineProperties():

configValues = {}

configValues[‘Name’]=”Live”

return configValues

So, I create a hash, put in a ‘Name’ key and value, then return the hash.  Now I have to import the propertiesLive.boo file and then call the function.  Here’s what I added to the Windsor.boo file:

//Change this to propertiesDebug.boo for Debug env

import file from propertiesDebug.boo

configEnvironment = DefineProperties()

This is right under the namespace import statements.  Now I can use the configEnvironment hash in my component registrations:

component “class.conn”, ConfigDepot:

ConnectionString = connectionString

ConfigEnvironment = configEnvironment[‘Name’]

You could easily add as many key/values as needed or put other logic in the DefineProperties() function.  The propertiesDebug.boo defines the same function, but with different values.

It’s not incredibly elegant, and I am betting Ayende or one of the other big brains could do it cleaner/better/stronger, but this works.

Next time….lifestyles.


The Bitter Coder Tutorials, Binsor Style IV: Switching Configs

Previous posts in the series:

In part four of his series, the Bitter Coder (Alex) shows how easy it is to switch configurations using Windsor.  Alex moves his config into a separate file and then comments out whichever configuration is not needed.  I am gonna take a different approach with Binsor, since we have the ability to use logic in the configuration.

Presuming we have 2 environments, dev and prod, and we want to deploy to both without manually switching configuration items.  (Note:  The big idea in this post is to show the logic, not the best practice.  I realize that keeping dev config info in a production file is icky.)  Anyway, let’s create a class that has a connection string, the ubiquitous configuraiton item:

public class ConfigDepot

{

public string ConnectionString{ get;set;}

}

So, we need something that is different between the development and production boxes to let us know which connect string to use.  For the purposes of this article, I am choosing the hostname.  Here is the Binsor:

machineName=System.Environment.MachineName

if machineName.ToUpper() == “DEVBOX”:

connectionString=”connStringDEV”

else:

connectionString=”connStringPROD”

component “class.conn”, ConfigDepot:

ConnectionString = connectionString

And the program….

static void Main(string[] args)

{

ConfigDepot cl = container.Resolve<ConfigDepot>();

Console.WriteLine(cl.ConnectionString);

}

When you run the program (which, um, defaults to the production conn string. Yikes!) and the name of your dev box is ‘DEVBOX’ then you’ll see “connStringDEV”.  Otherwise, you’ll see “connStringPROD”.

It’d be easy to add a slew of connection parameters here, but you should be wary of a couple of Booisms.  First, the if block is determined by the indention level.  So, everything that is indented the same amount is part of the block. (Check this out for code conventions.)  Also, the ‘if’ line and the ‘else’ line end in a colon ( : ) which is a bit odd.

Onward…next time we have Configuration Parameters.


The Bitter Coder Tutorials, Binsor Style III: Dictonaries

DictionaryImage via Wikipedia

Time for Part III in the Binsorization of the Bitter Coder tutorials.  The original tutorial is here.

The original tutorial created a class to handle word substitution, which looked a lot like:

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:

static void Main(string[] args)

{

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));

}

}

Now the Binsor:

import System

import System.Reflection

import System.Collections.Generic

import BitterCoder.Tutorials.Binsor.Core

aliases=Dictionary [of string, string]()

aliases[‘dog’]=”duck”

aliases[‘ate’]=”broke”

aliases[‘homework’]=”code”

component “aliases.service”, AliasService:

Aliases=aliases

So, we have a bit of strange syntax to get a generic Dictionary, but then it becomes very natural to create the entries.  Also, we don’t have to worry about the type converters that Alex mentions in his tutorial.

Running the code gives us:

a duck broke my code

All good.  Up next is Switching Configurations…

Zemanta Pixie

The Bitter Coder Tutorials, Binsor Style, Arrays

In the last post, I started doing the Bitter Coder tutorials, but using Binsor for the configuration.  This is the second in the series, and focuses on configuring arrays…the original is here.

So, our HolidayService tells us when we can go to the beach, yes?

namespace BitterCoder.Tutorials.Binsor.Core

{

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;

}

}

}

And the code to run this service:

static void Main(string[] args)

{

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();

}

And the config:

component “holiday.service”, HolidayService:

Holidays=(

DateTime(2007,12,24),

DateTime(2007,12,25),

DateTime(2008,1,1)

)

The array syntax in Binsor is the objects surrounding by parentheses.  If you has a list (or a List<DateTime>) you would have to use brackets ([ ]).  Also, we can new-up our dates here, minus the “new” keyword.  One more thing I’d like to mention, is I am constantly getting bit by not putting the colon (:) at the end of the component line, which you ONLY do if you are adding parameters.

BTW, if you take away the Holiday parameter (and the trailing : on the component line) you’ll get the default behavior, which shows up in the console as:

xmas is only for management!
new year, you haven’t done all the work for last year!

With the Holiday parameter (and the trailing : ) in the windsor.boo file, you get:

merry xmas!
happy new year

And we’re done with tutorial #2.

Next, we take a look at dictionaries…


The Bitter Coder Tutorials, Binsor Style

I blather on and on about Windsor and how I adore it, much to the annoyance of the other devs that are forced to work with me.  My last few uses of the Windsor container used Binsor as the configuration language, and some of my chums that are new to the Windsor/DI landscape have had to go from not using to Windsor to using it with Binsor.  There are not very many good Binsor tutorials out there that I could find, so I figured I would take some of the best Windsor tutorials and redo them using Binsor.  These tutorials are, of course, the Bitter Coder Tutorials on Windsor and they are wonderful.  I figured someone would have done this by now, but I couldn’t find it, so if this is a duplication of someone else’s effort, I duly apologize.

First off, a brief definition of Binsor.  Binsor is a Domain Specific Language (DSL) written in Boo with the specific purpose of configuring the Windsor container.  The “default” configuration option for Windsor (and most .NET based configuration approaches) is XML, which is fine.  However, XML can quickly get unwieldy, has no ability to perform any real logic, and (let’s face it) is just not sexy.

So, off we go, to the first tutorial, found here.

Simple Configuration

So, before we get to the code, in order to get Binsor to work, you’ll need the following references:

From Rhino Tools (http://sourceforge.net/projects/rhino-tools/)

  • Boo.Lang
  • Boo.Lang.Compiler
  • Boo.Lang.Extensions
  • Boo.Lang.Parser
  • Rhino.Commons.Binsor
  • Rhino.Commons.Clr
  • Rhino.DSL

From Castle (http://www.castleproject.org/)

  • Castle.Core
  • Castle.DynamicProxy2
  • Castle.MicroKernal
  • Castle.Windsor

My first solution has 2 projects, one class library and one console app.  The above references all go on the console app only.

Our tax calculator looks just like the Bitter Coder’s

namespace BitterCoder.Tutorials.Binsor.Core

{

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);

}

}

}

Here’s where we take a different path from the XML configuration.  Setting up the container looks for the Binsor script named here (“Windsor.boo”)  When using Binsor, make sure you set the right build properties for the .boo file.  In this case, we want it to be copied to the output directory.  If, however, you were working in a web environment, you could just mark the file as content and it’ll be copied to the root of your directory.  Now, let’s look at the console app and the setting up of the container:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Castle.Core;

using Castle.Windsor;

using Rhino.Commons.Binsor;

using BitterCoder.Tutorials.Binsor.Core;

namespace BitterCoder.Tutorials.Binsor.ConsoleTester

{

class Program

{

static void Main(string[] args)

{

IWindsorContainer container = new WindsorContainer().Install(BinsorScript.FromFile(“windsor.boo”));

TaxCalculator calculator = container.Resolve<TaxCalculator>();

decimal gross = 100;

decimal tax = calculator.CalculateTax(gross);

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

Console.Read();

}

}

}

So, still just one line…groovy.  We use the Rhino.Common.Bindsor.BinsorScript class to read windsor.boo and convert it to the parameters windsor needs.  Let’s look at the windsor.boo file now:

import System

import System.Reflection

import BitterCoder.Tutorials.Binsor.Core

component “tax.calculator”, TaxCalculator:

Rate=Convert.ToDecimal(0.25)

Five lines!  That’s it!  And now you see one of the reasons why people like to use Binsor.  It’s concise, readable, and can contain logic.  As you can see, I have access to any class in .NET that I wish to import, shown by my Convet.ToDecimal call to convert the rate to a decimal.

If you run the console app, you’ll see:  Gross: 100, Tax: 25.00 just like in the other tutorial.  Go ahead, mess with the rate and run it again.  It works.

So, that’s the first one down.  Next time we look at configuring arrays….

Zemanta Pixie