The Bitter Coder Tutorials, Binsor Style: XIV Startable Facilities October 16, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
add a comment
Previous posts in the series:
/// <summary>
/// Interface for components that wish to be started by the container
/// </summary>
public interface IStartable
{
/// <summary>
/// Starts this instance.
/// </summary>
void Start();
/// <summary>
/// Stops this instance.
/// </summary>
void Stop();
}
public class LameHttpServer:IStartable
{
private string _path;
private HttpListener _listener;
private Thread _listenerThread;
private ILogger _logger;
public ILogger Logger
{
get
{
if (_logger == null)
_logger = NullLogger.Instance;
return _logger;
}
set { _logger = value; }
}
public LameHttpServer(string prefix, string path)
{
_path = path;
_listener= new HttpListener();
_listener.Prefixes.Add(prefix);
}
public void Start()
{
Logger.Debug(“Starting LameWebService…”);
_listener.Start();
_listenerThread = new Thread(RequestWorker);
_listenerThread.Start();
Logger.Info(“LameWebService started…”);
}
public void Stop()
{
Logger.Debug(“Stopping LameWebService…”);
_listenerThread.Abort();
_listener.Stop();
Logger.Info(“LameWebService stopped.”);
}
private void RequestWorker()
{
while (true)
{
HttpListenerContext _context = null;
try
{
_context=_listener.GetContext();
} catch (ObjectDisposedException ex)
{
return;
}
ServeContext(_context.Response, _path);
}
}
private void ServeContext(HttpListenerResponse response, string _path)
{
string content = File.ReadAllText(_path);
byte[] buffer = Encoding.UTF8.GetBytes(content);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0 , buffer.Length);
output.Close();
}
}
facility "startable.facility", StartableFacility facility "logging.facility",LoggingFacility: loggingApi=LoggerImplementation.Console component "lame.http", LameHttpServer: prefix="http://*:8089/" path="lame.html"
So, we register the facilities discussed earlier. BTW, in order to resolve the facilities, I had to add the following to the top of Windsor.boo, in the import section:
import Castle.Facilities.Startable from Castle.MicroKernel import Castle.Facilities.Logging
Also, I added a reference to the Castle.Facilites.Logging assembly. I already had a reference for Castle.MicroKernel from a previous post.
Let’s look at our console code to crank up the server:
public static void Main(string[] args)
{
container = new WindsorContainer().Install(BinsorScript.FromFile(“windsor.boo”));
GetPage();
container.Dispose();
GetPage();
}
private static void GetPage()
{
Console.WriteLine(“\r\nClient: requesting http://localhost:8089/…”);
try
{
WebClient client = new WebClient();
string content = client.DownloadString(“http://localhost:8089/”);
Console.WriteLine(“Client: success, content follows.\r\n\r\n {0}”, content);
} catch (WebException ex)
{
Console.WriteLine(“Client: Exception occurred, message {0}”,ex.Message);
}
}
So, as can be seen above, we
- Create the container, which kicks off the server, coz it’s all Startable and stuff.
- Call GetPage().
- Dispose of the conatainer.
- Call GetPage() again.
- Wonder aloud of Alex minds plagiarism.
Here’s the results:
[Debug] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' Starting LameWebService... [Info] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' LameWebService started... Client: requesting http://localhost:8089/... Client: success, content follows. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title></title> </head> <body> <h1>Lame.html</h1> <h2>Welcome to lame.html file</h2> <p>This is the contents of the lame.html file, neat huh?</p> </body> </html> [Debug] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' Stopping LameWebService... [Info] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' LameWebService stopped. Client: requesting http://localhost:8089/... Client: Exception occurred, message Unable to connect to the remote server
The error at the end of the results is due to us disposing of the container, which decommisions all the components in the container. Alex explains this well…so read what he said.
So, I am gonna modify Alex’s final example where he demonstrates lifestyles and their effect on Startable facilities. The only difference, really, is I am going to show you what the Binsor looks like to control the lifestyle of a component.
Here’s our StartableExperiment:
public class StartableExperiment : IStartable
{
private static int _count;
private readonly int _number;
public StartableExperiment()
{
_number = ++_count;
}
#region IStartable Members
public void Start()
{
Console.WriteLine(“Started #{0}”, _number);
}
public void Stop()
{
Console.WriteLine(“Stopped #{0}”, _number);
}
#endregion
}
And the Binsor:
component "startable.exp", StartableExperiment: @lifestyle=LifestyleType.Transient
(You need to import Castle.Core to get the LifestyleType enum)
Running the following program code:
StartableExperiment exp1 = container.Resolve<StartableExperiment>();
container.Release(exp1);
StartableExperiment exp2 = container.Resolve<StartableExperiment>();
container.Release(exp2);
yields:
Started #1
Started #2
Stopped #2
Started #3
Stopped #3
Stopped #1
If I change the @lifestyle attribute in the Binsor to LifestyleType.Singleton, I get:
Started #1
Stopped #1
And that’s Startable Facilities and their lifestyles, from a Binsor point-of-view.
So, I hope someone enjoyed the series. Thanks again to Alex for his tutorials. They were a big rung in my learning ladder for Windsor.
I created a VS.NET project with all the code from this series. If you’re interested, hit me at glenn(dot)goodrich(at)gmail.com.
The Bitter Coder Tutorials, Binsor Style: Injecting Service Arrays October 6, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
add a comment
Previous posts in the series:
This post feeds off off Part 12 and is based on Alex’s post here. We are going to rework the last post and remove the decorator pattern. Instead, we’ll create a calculator that manages any number of other calculators, which are injected as an array.
So, in keeping with my shameless plagirizing of Alex’s code, here is the abstract class for our new calculators:
namespace BitterCoder.Tutorials.Binsor.Core
{
public abstract class AbstractCalculator
{
public abstract decimal Calculate(decimal currentTotal, Order order);
}
}
And now our total calculator:
using System.Linq;
namespace BitterCoder.Tutorials.Binsor.Core
{
public class TotalCalculator : AbstractCalculator
{
private static decimal CalculateTotal(Order order)
{
return order.Items.Sum(item => item.CostPerItem*item.Quantity);
}
public override decimal Calculate(decimal currentTotal, Order order)
{
return currentTotal + CalculateTotal(order);
}
}
}
And the GST calculator:
namespace BitterCoder.Tutorials.Binsor.Core
{
public class GSTCostCalculatorNoDecorator : AbstractCalculator
{
private decimal _gstRate = 1.125m;
public decimal GstRate
{
get { return _gstRate; }
set { _gstRate = value; }
}
private static bool IsNewZealand(Order order)
{
return (order.CountryCode == “NZ”);
}
public override decimal Calculate(decimal currentTotal, Order order)
{
if (IsNewZealand(order))
{
return (currentTotal*_gstRate);
}
return currentTotal;
}
}
}
The shipping calculator:
namespace BitterCoder.Tutorials.Binsor.Core
{
public class ShippingCalculatorNoDecorator : AbstractCalculator
{
private decimal _fragileShippingPremium = 1.5m;
private decimal _shippingCost = 5.0m;
public decimal ShippingCost
{
get { return _shippingCost; }
set { _shippingCost = value; }
}
public decimal FragileShippingPremium
{
get { return _fragileShippingPremium; }
set { _fragileShippingPremium = value; }
}
private decimal GetShippingTotal(Order order)
{
decimal shippingTotal = 0;
return order.Items.Sum(item =>
{
decimal itemShippingCost = ShippingCost*item.Quantity;
if (item.IsFragile) itemShippingCost *= FragileShippingPremium;
return shippingTotal += itemShippingCost;
});
}
public override decimal Calculate(decimal currentTotal, Order order)
{
return currentTotal + GetShippingTotal(order);
}
}
}
Lastly, our calculator of calculators, the reworked DefaultCalculator:
public class DefaultCalculatorNoDecorator : ICostCalculator
{
private readonly AbstractCalculator[] _calculators;
public DefaultCalculatorNoDecorator(AbstractCalculator[] _calculators)
{
this._calculators = _calculators;
}
public decimal CalculateTotal(Order order)
{
decimal currentTotal = 0;
return _calculators.Sum(calc => calc.Calculate(currentTotal, order));
}
}
So, we’ll inject an array of calculators (total, shipping, and gst) into our default calculator. Binsor, away!
component "default.calculator", ICostCalculator,DefaultCalculatorNoDecorator: _calculators=[@total.calculatornodec,@shipping.calculatornodec,@gst.calculatornodec] component "total.calculatornodec", AbstractCalculator,TotalCalculator component "gst.calculatornodec", AbstractCalculator, GSTCostCalculatorNoDecorator: GstRate=Convert.ToDecimal(1.20) component "shipping.calculatornodec", AbstractCalculator, ShippingCalculatorNoDecorator: FragileShippingPremium=Convert.ToDecimal(0.0)
Just like we did in our post on arrays, we inject an array of dependencies. Changing the order is just a matter of switching the order in the binsor. All good.
Running the program gives the same output as the last post.
Next post, which is the last in the series until Alex writes more (whew), is on the “Startable” facility.
The Bitter Coder Tutorials, Binsor Style: Part XII, Decorators October 1, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
1 comment so far
Image via Wikipedia
Previous posts in the series:
Today’s post focuses on Decorators. The Decorator Pattern is a well-known design pattern where functionality is added to a class by wrapping it with another class. Like an onion, sorta. Anyway, copying Alex, we are going to use this pattern with Windsor to chain implementations together.
Here is our Order and OrderItem classes:
public class Order
{
private readonly List<OrderItem> _items = new List<OrderItem>();
public List<OrderItem> Items
{
get { return _items; }
}
public string CountryCode { get; set; }
}
public class OrderItem
{
public OrderItem(string name, int quantity, decimal costPerItem, bool isFragile)
{
Name = name;
Quantity = quantity;
CostPerItem = costPerItem;
IsFragile = isFragile;
}
public bool IsFragile { get; set; }
public int Quantity { get; set; }
public decimal CostPerItem { get; set; }
public string Name { get; set; }
}
And an interface to calculate the cost of an order:
public interface ICostCalculator
{
decimal CalculateTotal(Order order);
}
Our default cost calculator (Side note: I like LINQ):
public class DefaultCostCalculator:ICostCalculator
{
public decimal CalculateTotal(Order order)
{
return order.Items.Sum(ord => ord.CostPerItem*ord.Quantity);
}
}
Our Binsor for the DefaultCostCalculator:
component "default.calculator", ICostCalculator,DefaultCostCalculator
Now, the program itself:
static void Main(string[] args)
{
var order1 = new Order
{
CountryCode = “NZ”,
Items =
{
new OrderItem(“water”, 10, 1.0m, false),
new OrderItem(“glass”, 5, 20.0m, true)
}
};
var order2 = new Order
{
CountryCode = “US”,
Items =
{
new OrderItem(“sand”, 50, 0.2m, false)
}
};
var _calc = container.Resolve<ICostCalculator>();
Console.WriteLine(“Cost to deliver Order 1: {0}”, _calc.CalculateTotal(order1));
Console.WriteLine(“Cost to deliver Order 2: {0}”, _calc.CalculateTotal(order2));
}
Running the program, gives us:
Cost to deliver Order 2: 10.0
Now, let’s go to New Zealand where we have to pay the Goods and Services Tax. Here is our cost calculator for that:
public class GstCostCalcualtorDecoarator : ICostCalculator
{
private readonly ICostCalculator _innerCalculator;
private decimal _gstRate = 1.125m;
public GstCostCalcualtorDecoarator(ICostCalculator innerCalculator)
{
_innerCalculator = innerCalculator;
}
public decimal GstRate
{
get { return _gstRate; }
set { _gstRate = value; }
}
#region ICostCalculator Members
public decimal CalculateTotal(Order order)
{
decimal innerTotal = _innerCalculator.CalculateTotal(order);
if (IsNewZealand(order))
{
innerTotal = (innerTotal*_gstRate);
}
return innerTotal;
}
#endregion
private bool IsNewZealand(Order order)
{
return (order.CountryCode == “NZ”);
}
}
And here’s the Decorator pattern. The GstCostCalculatorDecorator class accepts another ICostCalculator, then modifies the result by adding the GST. The DefaultCostCalculator is clueless to the GST, which is the beauty inherit in the pattern.
Let’s wire up the Binsor:
component "gst.calculator", ICostCalculator, GstCostCalculatorDecorator: innerCalculator=@default.calculator component "default.calculator", ICostCalculator,DefaultCostCalculator
We put the GST calculator first, so it’s the default implementation, and run the program:
Cost to deliver Order 1: 123.7500
Cost to deliver Order 2: 10.0
So, the US one hasn’t changed, as expected. Finally, let’s add a shipping calculator:
public class ShippingCostCalculatorDecorator : ICostCalculator
{
private readonly ICostCalculator _innerCalculator;
public decimal ShippingCost { get; set; }
public decimal FragileShippingPremium { get; set; }
public ShippingCostCalculatorDecorator(ICostCalculator innerCalculator)
{
_innerCalculator = innerCalculator;
ShippingCost = 5.0m;
FragileShippingPremium = 1.5m;
}
#region ICostCalculator Members
public decimal CalculateTotal(Order order)
{
decimal innerTotal = _innerCalculator.CalculateTotal(order);
return innerTotal + GetShippingTotal(order);
}
#endregion
private decimal GetShippingTotal(Order order)
{
return order.Items.Sum(item =>
{
var itemShippingCost = ShippingCost*item.Quantity;
if (item.IsFragile) itemShippingCost *= FragileShippingPremium;
return itemShippingCost;
});
}
}
And add our Binsor, making sure it’s the first ICostCalculator implementation in the file:
component "shipping.calculator", ICostCalculator, ShippingCostCalculatorDecorator: innerCalculator=@gst.calculator
Run it.
Cost to deliver Order 1: 211.2500
Cost to deliver Order 2: 260.0
As Alex points out, we are calculating our GST before shipping, which is kinda stoopid. The Decorator Pattern saves our bacon here, as we can just swap things around (oh, and we change some parameters too):
component "gst.calculator", ICostCalculator, GstCostCalculatorDecorator: innerCalculator=@gst.calculator GstRate=1.20 component "shipping.calculator", ICostCalculator, ShippingCostCalculatorDecorator: innerCalculator=@default.calculator FragileShippingPremium=0.0 component "default.calculator", ICostCalculator,DefaultCostCalculator
Run it one more time:
Cost to deliver Order 1: 211.2500
Cost to deliver Order 2: 260.0
So, that’s that. Alex has some great comments in his post about other stuff you can do with the Decorator pattern, so I highly recommend you read his all the way through.
Next time we’ll do this stuff without decorators….
The Bitter Coder Tutorials, Binsor Style: Part XI, Factories September 9, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
2 comments
Previous posts in the series:
In this post, I will be discussing how to use Binsor to configure the factory support facility in Windsor. A “facility” is (as Alex states) an add-in to the Windsor container that changes or adds what the container can do. Facilities are a big part of what makes Windsor so freaking kick-ass, and other facilities are the logging facility, the transaction facility, and (the oft blogged about here) WCF facility.
So, let’s get to the code. Here’s our interface:
public interface ISmsService
{
void SendMessage(string number, string message);
}
And our SmsService and SmsConfig classes:
public class SmsService : ISmsService
{
private SmsConfig _config;
public void SetConfig(SmsConfig config)
{
_config = config;
}
public void SendMessage(string number, string message)
{
Console.WriteLine(“SMS Message: {0} sent to {1} with account {2}”, message, number, _config.UserName);
}
}
public class SmsConfig
{
private string _userName;
private string _password;
private int _retryAttempts{ get; set;}
internal string UserName
{
get { return _userName; }
}
internal string Password
{
get { return _password; }
}
public void SetCredentials(string user, string pwd)
{
_userName = user;
_password = pwd;
}
}
Now, showing what is necessary to instantiate our SmsService class:
SmsService service = new SmsService();
SmsService.SmsConfig config = new SmsService.SmsConfig();
config.SetCredentials(“joe”, “secret”);
config.RetryAttempts = 3;
service.SetConfig(config);
That is not gonna work with Windsor straight away. So, we need a factory to take care of this for us:
public class SmsServiceFactory
{
private string _userName;
private string _password;
private int _retryAttempts { get; set; }
public SmsServiceFactory(string userName, string password)
{
this._userName = userName;
this._password = password;
_retryAttempts = 3;
}
public ISmsService CreateService()
{
SmsService service = new SmsService();
SmsConfig config = new SmsConfig();
config.SetCredentials(_userName,_password);
service.SetConfig(config);
return service;
}
}
Right. Now we have to get our supporting Binsor squared away. First off, let’s register the facility. Add the following import statement to the top of your .boo file:
import Castle.Facilities.FactorySupport from Castle.MicroKernel
So, Binsor knows where to get the facility. Then, the facility itself:
facility FactorySupportFacility
Now we have to add our factory and our component:
component "smsservice.factory", SmsServiceFactory: userName="joe" password="secret" component "smsservice.default", ISmsService,SmsService: @factoryId=@smsservice.factory @factoryCreate="CreateService"
Last, but not least, the program:
private static void Main(string[] args)
{
container = new WindsorContainer().Install(BinsorScript.FromFile(“windsor.boo”));
ISmsService smsService = container.Resolve<ISmsService>();
smsService.SendMessage(“+465556555″, “testing testing…1.2.3″);
Console.Read();
}
Running the console, gives us:
SMS Message: testing testing…1.2.3 sent to +465556555 with account joe
Seems we’re looking at the Decorator Pattern with Windsor next…
The Bitter Coder Tutorials Binsor Style, Part X: Setter Injection September 2, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
1 comment so far
Previous posts in the series:
So, we’re 10 posts into our arguable plagerism of Alex’s tutorials, and this post’s focus is setter injection. Setter injection is, basically, exposing a class’s dependencies via properties, as opposed to constructor parameters. I prefer setter injection only when the number of dependencies is very high, and in most of those cases, it’s probably code smell. However, we are just here to Binsorify the Bitter Coder Tutorials, so off we go.
We are slightly refactoring the project from Part 9, adding the ability to specify a formatter for our encoded message. The interface is here:
public interface IMessageFormatter
{
string FormatMessage(string from, string to, string body);
}
Here’s the default formatter:
public class DefaultFormatter:IMessageFormatter
{
public string FormatMessage(string from, string to, string body)
{
return string.Format(“to: {0}\r\nfrom: {1}\r\n\r\n{2}”, to, from, body);
}
}
And the refactored version of last post’s message sender, incorporating our new dependency:
public class SecretMessageSender
{
private readonly IEncoder _encoder;
private readonly string _from;
public SecretMessageSender(IEncoder _encoder, string _from)
{
this._encoder = _encoder;
this._from = _from;
}
public void SendMessage(string to, string body)
{
Console.WriteLine(“to: {0}\r\nfrom: {1}\r\n\r\n{2}”, to, _from, _encoder.Encode(body));
}
}
Looking at the config now, we have:
component “default.formatter”, IMessageFormatter, DefaultFormatter
component “messageformat.sender”, FormatMessageSender:
_from=”ruprict@wordpress.com”
_encoder=@null.encoder
Notice that we don’t specifically set the Formatter in the config, so Windsor will do that for us. Running the program now will yield the same results as the last post. Keeping with Alex’s tutorial, let’s make another formatter, this one based on the NVelocity template engine. NVelocity has changed a good bit since Alex used it in his tutorial, so the code is a bit more complex (thanks for the help on this, Alex):
public class NVelocityMessageFormatter : IMessageFormatter
{
private readonly Template _template;
private readonly VelocityEngine _velocity;
public NVelocityMessageFormatter(string _templateFile)
{
_velocity = new VelocityEngine();
var props = new ExtendedProperties();
props.SetProperty(RuntimeConstants.RESOURCE_LOADER, “file”);
props.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH,
Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName));
props.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, “false”);
_velocity.Init(props);
_template = _velocity.GetTemplate(_templateFile);
}
#region IMessageFormatter Members
public string FormatMessage(string from, string to, string body)
{
var context = new VelocityContext();
context.Put(“from”, from);
context.Put(“to”, to);
context.Put(“body”, body);
context.Put(“today”, DateTime.Now);
var writer = new StringWriter();
_template.Merge(context, writer);
return writer.ToString();
}
#endregion
}
Our formatter merges the parameters (from, to, and body) with the template, which looks like:
To: $to
From: $from
Sent: $today
———————-
$body
———————-
Finally, let’s see how we configure the program to use our fancy new formatter:
component “fancymessage.formatter”, IMessageFormatter, NVelocityMessageFormatter:
_templateFile=”message.vm”
component “messageformat.sender”, FormatMessageSender:
_from=”ruprict@wordpress.com”
_encoder=@null.encoder
Formatter = @fancymessage.formatter
We specify the template file as well as the “Formatter” parameter. Our output now looks like:
To: hammett
From: ruprict@wordpress.com
Sent: 8/25/2008 9:49:39 AM
———————-
Howzit going at Microsoft?
———————-
And we’re done. We covered a decent amount of stuff in this post: setter injection, default dependencies, overriding default dependencies, as well as how to use NVelocity as a template engine.
Next time….factories.
The Bitter Coder Tutorials, Binsor Style: Part IX, Constructor Injection August 21, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
1 comment so far
Previous posts in the series:
Part 9 of the original series focuses in on Constructor Injection, which is one method of doing Dependency Injection (the other is Setter Injection, which we’ll get to) The reason to use Constructor or Setter Injection is a bit subjective, but (to me) boils down to if you the paramters to be mandatory and how many parameters you have. We’re not here to debate, though, we’re here to copy Alex’s hard work….
Here’s the interface Alex defines;
public interface IEncoder
{
string Encode(string source);
}
And the two encoders:
public class NullEncoder:IEncoder
{
public string Encode(string source)
{
return source;
}
}
public class SillyEncoder:IEncoder
{
private char[] _mixedUp = “YACBDFEGIHJLKMONPRSQTUWVXZ”.ToCharArray();
public string Encode(string source)
{
string upperSource = source.ToUpper();
char[] encoded = new char;
for (int i = 0; i < encoded.Length; i++)
{
encoded[i] = MapCharacter(upperSource[i]);
}
return new string(encoded);
}
private char MapCharacter(char ch)
{
if ((ch >= ‘A’) && (ch <= ‘Z’))
{
return _mixedUp[ch - 'A'];
}
return ch;
}
}
Let’s check out the binsor:
component “null.encoder”, IEncoder, NullEncoder
component “silly.encoder”, IEncoder, SillyEncoder
component “message.sender”, SecretMessageSender:
_from=”ruprict@wordpress.com”
Notice we didn’t specify a value for the “_encoder” parameter, so Windsor will just plug in the first one it finds. And, finally, the Program:
private static void Main(string[] args)
{
var sender = container.Resolve<SecretMessageSender>();
sender.SendMessage(“hammett”,“Howzit going at Microsoft?”);
}
Running this as is, gives us:
to: hammett
from: ruprict@wordpress.com
GOWZIQ EOIME YQ KICROSOFQ?
So, what if we want to send an unencrypted message? Well, we can specify which IEncoder component to wire to our sender, like so:
component “message.sender”, SecretMessageSender:
_from=”ruprict@wordpress.com”
_encoder=@null.encoder
See? We refer to it by the name we gave the component. Running it now, gives us:
to: hammett
from: ruprict@wordpress.com
Howzit going at Microsoft?
(I bet he’s doing great…)
Setter injection…coming up!
The Bitter Coder Tutorials VIII: Referencing Instances By Key August 18, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
add a comment
Previous posts in the series:
In tutorial #8, Alex continues down his path of switching implementations around, but this time we are going to have multiple components that implement the same contract, and we’ll specify which one we want by id. The id we are talking about is the id we gave the component when we registered it with Windsor. Enough blah, blah, onto the code.
Here’s our class to read a file:
public class FileReader
{
public string FileName { get; set; }
public string ReadToEnd()
{
return File.ReadAllText(FileName);
}
}
Now, we’ll register two components with the container, each one reading a different file.
component “file1.reader”, FileReader:
FileName=”file1.txt”
component “file2.reader”, FileReader:
FileName=”file2.txt”
Finally, the program code:
static void Main(string[] args)
{
FileReader defaultReader = container.Resolve<FileReader>();
FileReader file1Reader = container.Resolve<FileReader>(“reader.file1″);
FileReader file2Reader = container.Resolve<FileReader>(“reader.file2″);
Console.WriteLine(“Default contents: {0}”, defaultReader.ReadToEnd());
Console.WriteLine(“File1 contents: {0}”, file1Reader.ReadToEnd());
Console.WriteLine(“File2 contents: {0}”, file2Reader.ReadToEnd());
}
Adding the text files and running this bad boy gives the output:
Default contents: This is the contents of file 1
File1 contents: This is the contents of file 1.
File2 contents: This is the contents of file 2.
So, as Alex says, the default implementation is the first one in the file, just like using XML.
In his tutorial, Alex gives another example of why you would need to reference implementations by id, so if you’re interested, you can read it there (although, you shoulda already read that post…right?)
Next time, constructor injection…
The Bitter Coder Tutorials, Binsor Style VII: Switching Implementations August 11, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
add a comment
Previous posts in the series:
In tutorial #7, Alex shows us the real meat of DI, which is switching out implementations. This is where I had my “A-HA!” moment with Windsor and where I continue to see the most obvious value.
As Alex states, when switching implementations, you take the contract of your implementation and stuff it in an interface. Here’s the interface for our example:
public interface IMessageOfTheDay
{
string GetMessageOfTheDay();
}
And the same two implementations from Alex:
public class StaticMessageOfTheDay:IMessageOfTheDay
{
private string _message;
public string Message
{
set { _message = value; }
}
public string GetMessageOfTheDay()
{
return _message;
}
}
And #2:
public class WikiQuotesMessageOfTheDay : IMessageOfTheDay
{
public string GetMessageOfTheDay()
{
WebClient client = new WebClient();
string content = client.DownloadString(“http://en.wikiquote.org/wiki/Main_Page”);
string toFind = “<td align=\”center\”>”;
int start = content.IndexOf(toFind) + toFind.Length + 56;
int length = content.IndexOf(“<a”, start) – start;
return content.Substring(start, length);
}
}
(I had to change the string that Alex was searching on and hardcode a length to the beginning of the quote, so maybe I’ll rename this class to HorrificQuoteOfTheDay or something)
So, let us get to the Binsor config. First off, I put my interface in a separate namespace, so I had to add an import clause to the top of the Windsor.boo file. Then, I add the StaticMessageOfTheDay component:
import BitterCoder.Tutorials.Binsor.Core.Interfaces
component “motd.service”,IMessageOfTheDay,StaticMessageOfTheDay:
message=”Welcome to my Binsor tutorials”
Now, when I run the project, I get:
MOTD: Welcome to my Binsor tutorials
Changing out the motd.service component for the Wiki Quotes:
component “motd.service”,IMessageOfTheDay,WikiQuotesMessageOfTheDay
The running program now gives:
MOTD: Those works of art which have scooped up the truth and presented it to us
as a living force â?” they take hold of us, compel us, and nobody ever, not even
in ages to come, will appear to refute them. ~
It’s just that easy. Our quote is from Aleksandr Solzhenitsyn, whom I can safely say I’ve never heard of before, but I will take as a sign that this blog post is a work of art.
Next time, switching implementations by id….
The Bitter Coder Tutorials, Binsor Style VI: Switching Lifestyles August 4, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
2 comments
Previous posts in the series:
In tutorial #6, Alex discusses lifestyles and how to muck about with them. If you are unfamiliar with what lifestyles are in this context, go read his post first (which you should be doing anyway)
So, we create the same adding service component (minus the spelling errors
):
public class AddingService
{
private int _total = 0;
public void AddAmount(int amount)
{
_total += amount;
}
public int Total
{
get { return _total; }
}
}
And we add it to the Windsor configuration, like so:
component “adding.service”, AddingService
Nothing special. When we run the code we get:
You have counted 75 sheep and herded 75 angry cats
This seems a bit odd, as the container is using the same instance for both AddingService requests. Let’s make it give us a new one for each request. This is accomplished by adding the “lifestyle” attribute to the component:
component “adding.service”, AddingService:
@lifestyle=”transient”
Notice the “@” sign, which tells Binsor to put this attribute on the Windsor component, but not the class instance (I can’t figure out a better way to word that.) Now, when we run it, we get:
You have counted 60 sheep and herded 15 angry cats
Snot on. Alex goes on to say how you can add an attribute on the class to indicate it’s lifestyle. That isn’t really relevent to what I’m doing here, but you should check it out all the same.
Coming up….Switching Implementations, which is where a DI container really starts to make sense.
The Bitter Coder Tutorial, Binsor Style V – Configuration Parameters July 28, 2008
Posted by ruprict in Castle.Tags: Binsor, Windsor
1 comment so far
(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.
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=991f1dfc-6539-437b-96b0-d66cf45f8c69)
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=04592086-90e5-4bbe-a232-eed6ad71b121)
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=58ac3891-3867-4c08-8335-4d38492ab773)