The Bitter Coder Tutorials, Binsor Style: XIV Startable Facilities

Previous posts in the series:

The last (until Alex writes more) of our Bitter Binsor tutorials is here.  Today, we focus on the Startable Facility, which is explained in Alex’s post.  The link to the wiki in Alex’s post is no good, so try here for more info on the facility.  Basically, something is startable if it has the Start/Stop controllable lifecycle, like a web server.  In Castle, to be considered Startable you have to implement the IStartable interface:

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

}

Once you register the Startable Facility with the Windsor Container, it will attempt to create and call .Start() on any startable component, provided all the dependencies have been satisfied.  So, every time a component is registered with the container, Windsor checks to see if a startable component has all dependencies satisfied and can be started.  Alex discusses the startable facility more in his post, so make sure you read it too.
Let’s create the LameHttpServer using this code:

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

}

}

Looking at the class, we need a couple of configuration parameters as well as a dependency on  ILogger.  We’ll use the Castle Logging Facility for that, which is probably the facility I use most.  You should check it out.  Anyway, here’s our Binsor:
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/…&#8221;);

try

{

WebClient client = new WebClient();

string content = client.DownloadString(http://localhost:8089/&#8221;);

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

  1. Create the container, which kicks off the server, coz it’s all Startable and stuff.
  2. Call GetPage().
  3. Dispose of the conatainer.
  4. Call GetPage() again.
  5. 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.

Advertisements

About Ruprict

I am a nerd that is a Nerd Wannabe. I have more kids than should be allowed by law, a lovely wife, and a different sense of humor than most. I work in the field of GIS, where I am still trying to find myself on the map. View all posts by Ruprict

One response to “The Bitter Coder Tutorials, Binsor Style: XIV Startable Facilities

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: