Wednesday, January 16, 2008

Ninject Message Broker

I updated my local copy of Ninject today and decided to try out the message broker. I opened the test fixture to see how it is used and wrote up this little test.  Overall I am very happy with how this simple demo worked out. I am going to try to set aside some time to try something more in depth. This simple example has one object getting the current time from the Internet and then publishes the new time it received. The second object listens for the time to be updated and then writes it to the console. What I really dig is that the two objects never know of one another.

 

internal class Program
{
private static IKernel _kernel;

private static void Main(string[] args)
{
// Intialize our injection kernel
_kernel = new StandardKernel();

// Add message broker functionality.
_kernel.Connect<IMessageBroker>(new StandardMessageBroker());

// Get the event publisher. It reads the current time and fires an event
TimeReader pub = _kernel.Get<TimeReader>();
Debug.Assert(pub != null);

// Get the subscriber, it waits to get the current time and writes it to stdout
TimeWriter sub = _kernel.Get<TimeWriter>();
Debug.Assert(sub != null);

// Verify that they were wired together
Debug.Assert(pub.HasListeners);
Debug.Assert(sub.LastMessage == null);

// Get the current time. It should automatically let the TimeWriter know
// without either of them ever knowing of one another.
pub.GetCurrentTime();

// Wait to exit.
Console.ReadLine();
}
}

internal class TimeWriter
{
private string _lastMessage;

public string LastMessage
{
get { return _lastMessage; }
set { _lastMessage = value; }
}

[Subscribe("message://Time/MessageReceived")]
public void OnMessageReceived(object sender, EventArgs<string> args)
{
_lastMessage = args.EventData;
Console.WriteLine(_lastMessage);
}
}

internal class TimeReader
{
public bool HasListeners
{
get { return (MessageReceived != null); }
}

[Publish("message://Time/MessageReceived")]
public event EventHandler<EventArgs<string>> MessageReceived;


/// <summary>
/// Gets the current time and updates all subscribers.
/// </summary>
public virtual void GetCurrentTime()
{
string text = GetWebPage();
Regex regex = new Regex(@"<b>\d\d:\d\d:\d\d<br>");
Match match = regex.Match(text);
string time = match.Value.TrimStart("<b>".ToCharArray()).TrimEnd("<br>".ToCharArray());
SendMessage(time);
}

/// <summary>
/// Gets the contents of a web page as a string.
/// </summary>
/// <returns></returns>
private static string GetWebPage()
{
string url = "http://www.time.gov/timezone.cgi?Eastern/d/-5";
HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
webRequest.Method = "GET";
using (WebResponse webResponse = webRequest.GetResponse())
{
using (StreamReader sr = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
}

/// <summary>
/// Sends the message to all subscribers in a threadsafe manner.
/// </summary>
/// <param name="message">The message.</param>
public void SendMessage(string message)
{
EventHandler<EventArgs<string>> messageReceived = MessageReceived;

if (messageReceived != null)
{
messageReceived(this, new EventArgs<string>(message));
}
}
}