One of my friends told me that he didn't understand Lifestyles concept in Castle Windsor. Event though the documentation is very clear, wrote him a very simple application to explain the concept. Before I jump into the code, let me repeat the information from the document first :).
Lifestyles help us to tell the Windsor container to how we want our components to be created. Castle Windsor gives us 5 different Lifestyles to accommodate our needs for different needs. Here is the list:
- Singleton (the default): As the name implies, only one instance of the component will be created, so when the object is request from the container, the object will be created once, and after request swill get a copy of the first request created object. This is the default behavior of the container.
- Transient: For each request from the container, a new instance for that object will be created.
- PerThread: It is singleton per thread, so within the same thread, all request will the same object, different threads will get new objects
- Pooled Instances: objects will be pooled to avoid unnecessary constructors
- Custom: what ever you code :)
Of course this information is same as in the documentation, and my friend ask me a demo, so let’s create one. In my demo, i will create a console application, so go ahead a create a demo application named: WindsorLifeStyles. Add references to: Castle.Core.dll ,Castle.MicroKernel.dll, Castle.Windsor.dll, Castle.DynamicProxy.dll
Let’s add a very simple interface to our project:
public interface INotifier
{
int MessageCounter { get; }
string GetMessage();
}
If we drive a class from this interface, such as a StringNotifier class, it could be as simple as this:
public class StringNotifier : INotifier
{
private int MessageCounter_;
public int MessageCounter
{
get { MessageCounter_++;
return MessageCounter_;
}
}
public string GetMessage()
{
return string.Format("MessageCounter: {0}", MessageCounter);
}
}
There is no magic here, a class with a getter to a private variable, and each time, the value is read, it is incremented. Also a function that returns a string with the counter. Now we need a class that uses our StringNotifier class, let’s call this NotifyClient, and here is the code:
1: public class NotifyClients
2: {
3: private INotifier notifier;
4:
5: public NotifyClients(INotifier notifier)
6: {
7: this.notifier = notifier;
8: }
9:
10: public void SendMessage(string msg)
11: {
12: string suffix = notifier.GetMessage();
13: Console.Out.WriteLine("Message from {0}, {1}",msg,suffix);
14: }
15: }
This is class that uses INotifer interface we defined, and in its contructor it takes it as a parameter. We have a dependency here. The SendMessage function merges the INotify().GetMessage() result with a parameter that is passed to it, and prints it to the console. It is time to code our Main function and also register our objects to the container. First let’s create the container:
IWindsorContainer container = new WindsorContainer();
After creating the container, it is time to register our classes to the container, so that we can call them later and also resolve the dependencies. Here is 2 lines of code that register the objects:
container.AddComponent("NotifyClients",typeof(NotifyClients));
container.AddComponent("StringNotifier",typeof(INotifier),typeof(StringNotifier));
It is time to consume the objects now, I will ask to the container to give me three NotifyObjects, and then call the SendMessage function:
1: NotifyClients notify1 = (NotifyClients)container["NotifyClients"];
2: notify1.SendMessage("notify1");
3:
4: NotifyClients notify2 = (NotifyClients)container["NotifyClients"];
5: notify2.SendMessage("notify2");
6:
7: NotifyClients notify3 = (NotifyClients)container["NotifyClients"];
8: notify3.SendMessage("notify3");
Before you run the application, can you guess the result? Here is the result:
Message from notify1, MessageCounter: 1
Message from notify2, MessageCounter: 2
Message from notify3, MessageCounter: 3
As you can see the counter is incremented, even if the ask the container to give us a brand new object, this happened because by default container uses Singleton Lifestyles and only and only 1 instance is created with this model. What if we want a completely brand new object each time we request it? then we have to change the lifestyle for that object. Go back to your StringNotifier class and add [Transient] attribute to your class so that it looks :
[Transient]
public class StringNotifier : INotifier
{ .....
Do the same thing for NotifyClient class, and run the application again, this time you will see that the MessageCounter is always 1 as for each request object, container created a brand new one. You can apply the other lifestyles and test your application but hope this brief introduction helps :)
Let the power surround you
Volkan
Tags: