Tuesday, November 13, 2007

Creating a Custom Binsor Lifestyle

I'm currently evaluating Windsor (well, Ayende's Binsor interpretation of it to be more precise) to help alleviate some UI stresses in a WinForms application. Essentially I am looking for something that allows me to track a certain UI context. For example, I have broken down the application flow into a number of key contexts: Application (user login), Project, Widget. I would like each context to build upon the previously loaded contexts and when a context is ended I want to clear data associated with it. For example repositories, caches, unsaved changes, etc.

Since our project is using the Castle Project's Windsor Container it seemed like a natural place to start implementing this functionality. My first kick at this cat involved a facility that managed contexts and the data associated with each one, however, I quickly realized that my facility was mimicking the behaviour of a Lifestyle. Basically what I wanted was the ability to resolve components as per-context singletons so I decided to try and create a Custom Lifestyle to achieve it.

The first step is to create a Lifestyle Manager. I just derived a class from the MicroKernel AbstractLifestyleManager and implemented the Resolve Method:

public class ContextualLifestyleManager : AbstractLifestyleManager

{

private const string CONTEXT_ATTRIBUTE = "context";

private readonly IDictionary<Type, IContext> contextMap = new Dictionary<Type, IContext>();

private readonly IDictionary<IContext, IDictionary<Type, object>> contextualComponentMap = new Dictionary<IContext, IDictionary<Type, object>>();


public override object Resolve(CreationContext context)

{

Type contextType = RegisterApplicationContext(context);

IContext appContext = contextMap[contextType];

string serviceTypeName = context.Handler.ComponentModel.Service.FullName;

Type serviceType = Type.GetType(serviceTypeName);

if (!contextualComponentMap[appContext].ContainsKey(serviceType))

{

contextualComponentMap[appContext].Add(serviceType, base.Resolve(context));

}

return contextualComponentMap[appContext][serviceType];

}


private Type RegisterApplicationContext(CreationContext context)

{

string contextTypeName = context.Handler

.ComponentModel

.Configuration

.Attributes[CONTEXT_ATTRIBUTE];

Type contextType = Type.GetType(contextTypeName);

if (!contextMap.ContainsKey(contextType))

{

IContext appContext = (IContext) Kernel.Resolve(contextType);

appContext.Ended += HandleContextEnded;

contextMap.Add(contextType, appContext);

contextualComponentMap.Add(appContext, new Dictionary<Type, object>());

}

return contextType;

}

}


Keep in mind that you can override resolve to do whatever your heart desires... in this snip you can see I'm grabbing the name of the Service I'm requesting and also an Attribute from the ComponentModel configuration. Basically anything in the kernel is at your mercy!

Now, I also wanted to clean up after the context ends so added an event handler to respond to the IContext.Ended event:

private void HandleContextEnded(object sender, EventArgs e)

{

IContext context = (IContext) sender;

Console.WriteLine(string.Format("Removing context: {0}", context.Name));

context.Ended -= HandleContextEnded;

contextMap.Remove(context.GetType());

contextualComponentMap.Remove(context);

}


Now, I know its not pretty, but it does the trick for a proof of concept. :-)

The next step was to configure this custom lifestyle in the boo container configuration. I got stuck on this for a while but eventually created a LifestyleExtension to help me out:

public class Contextual : LifestyleExtension

{

private readonly Type customLifestyleType = typeof(ContextualLifestyleManager);

public Contextual() : base(LifestyleType.Custom)

{

}

protected override void AddLifestyleDetails(IConfiguration configuration)

{

configuration.Attributes["customLifestyleType"] = string.Format("{0}, SpikeWinForms", customLifestyleType.FullName);

}

}


Here is what my Binsor config file ended up looking like (hint: @context is an attribute!):

component repository, IRepository, Repository:

lifestyle Contextual

@context = MasterContext

component applicationContext, ApplicationContext, ApplicationContext

component masterContext, MasterContext, MasterContext


Anyway, hope this post helps you out if you're trying to create custom Lifestyles using Binsor.

Friday, November 02, 2007

Get Your Strings To Perform

Alright, we are probably all aware that strings are well employed in applications. We use them to display information to the user, we abuse them in dynamic sql statements and we confuse them with type definitions through their use in reflection. I'm willing to bet that if we inspected application's memory, strings would represent the majority of bytes. Not that there's anything wrong with that. After all the CLR has some pretty cool tweaks to make strings as primitive and performant as possible. Unfortunately for us... the CLR's string nyahh is sometimes not enough.

There are a few important things to remember about strings in C#. First, they are immediately derived from Object making them a reference type and living on the heap. The second important fact about strings is that they are an immutable array of characters. That means, they can not be altered in any way after they are constructed. The immutability of strings allows us to do some funky things without worrying about altering the original string.

Take the following code snip for example:

string message = "Hello World";

Console.WriteLine(message);

Console.WriteLine(message.Replace("Hello", "Adios")

.Replace("World", "Suckah")

.ToUpper());

Console.WriteLine(message);



The result of running this is:
Hello World
ADIOS SUCKAH
Hello World

The string contained in the message variable is unchanged while each method returns a newly created string. It is important to understand that line 3 of this snip actually constructs three different string objects on the heap and then lets leaves them for the garbage collector to clean up. Its easy to see then that if many operations are performed on a string we could quickly run into a large amount of memory being managed. It is preferred, for that reason, to use the StringBuilder class if you are doing many string manipulation operations.

Another bonus about strings being immutable is that they are inherently thread safe. Since there are no thread synchronization issues the the CLR can help you reduce the number of actual strings allocated in memory by sharing them as a single string object. This is the concept of string interning. You should consider using string interning when your code has many instances of the same string value (wasted memory) or if you are doing many checks for equality (expensive operation).

Note: String equality can get expensive because if the strings are the same length, they are checked character by character.

The CLR contains an internal hash table of strings mapped to actual string objects on the heap. You can access this hash table through two static methods on the String object itself:
public static string Intern(string str);
public static string IsInterned(string str);

The Intern method takes a string as a parameter and checks in the internal hash table for a reference to a matching string object that has already been allocated in memory. If one exists that reference is returned. Otherwise it makes a copy of your string, adds it to the hash table and returns a reference to the copy.

The IsInterned method behaves very similar except if the string does not exist in the hash table null is returned.

The end result is a single string being allocated in memory. These methods assist in both reducing memory consumption by reducing the total number of strings allocated on the heap as well as increased performance by replacing ordinal string comparisons with a quick pointer comparison.

So go ahead and run the following code snip:

string message1 = "Hello World";

string message2 = "Hello World";

Assert.IsFalse(ReferenceEquals(message1, message2));


Um, they were the same... heh. Turns out the CLR interns all literal strings described in an assembly's metadata. This is where the ECMA specifications for string interning gets confusing. It seems that by default the CLR will try and intern literal strings for us, but, this can be disabled by adding the CompilationRelaxations.NoStringInterning flag to the assembly:

[assembly : CompilationRelaxations(CompilationRelaxations.NoStringInterning)]


But, the ECMA also states that the CLR may choose not to intern all of the strings in an assembly's metadata. So in reality, you can still end up with string interning by default. Additionally, there are no guarantees that future versions of CLR will honor this flag. So, the long and short of this is that you should only count on interning if you explicitly write code that uses the Intern or IsInterned methods. The following code snip demonstrates how to do this:

string intern1 = String.Intern(message1);

string intern2 = String.Intern(message2);

Assert.IsTrue(ReferenceEquals(intern1, intern2));


By the way, to prove that interning doesn't work on non literal strings you can concatenating strings:

string message1 = "Hello";

message1 += " World";

string message2 = "Hello World";

Assert.IsFalse(ReferenceEquals(message1, message2));


So, there you go. Some tips and pitfalls of string performance.

 
s