Registering components through code
To get things moving, we need to create a Windsor Container instance and start registering components into it. This allow the container to act on the components. Let's start by registering our Form1 class on the container.
using Castle.Windsor; public class App { public static void Main() { IWindsorContainer container = new WindsorContainer(); // Register the component container.AddComponent("form.component", typeof(Form1)); // Request the component to use it Form1 form = (Form1) container[typeof(Form1)]; // Use the component Application.Run(form); // Release it container.Release(form); } }
You can run the application and certify that it works as expected.
Now let's create a few mock services to mimic a real application. For example, let's create a HttpServiceWatcher. In the real world this watcher would make requests from time to time to a Http server to make sure it is running.
What if the server is not running? Well, it should definitely do something. Should it send an email to someone? Should it start an alarm? Even if it needs to do these two things, where should this code go?
If your answer is, let's code HttpServiceWatcher in a way that it is capable of sending emails and sound alarms, then you should read more about Separation of Concerns. As the name imples, the HttpServiceWatcher should only watch the http service status. The logic to send emails or sound alarms can be put on different implementation of an IFailureNotifier service.
Our service can look like the following:
namespace GettingStartedPart1 { using System; public class HttpServiceWatcher { public void StartWatching() { } public void StopWatching() { } } }
We can then create the IFailureNotifier and a few implementations like EmailFailureNotifier and AlarmFailureNotifier:
namespace GettingStartedPart1 { using System; public interface IFailureNotifier { void Notify(); } }
namespace GettingStartedPart1 { using System; public class EmailFailureNotifier : IFailureNotifier { public void Notify() { // Send email to admins } } }
namespace GettingStartedPart1 { using System; public class AlarmFailureNotifier : IFailureNotifier { public void Notify() { // Turn on alarm } } }
But how or HttpServiceWatcher can gain access to a notifier? We can use a constructor or a property, depends on the semantics. Ask yourself these questions:
- Does it make sense to have a watcher without a notifier?
- If a failure is detected, and no notifier exists, what should the watcher do?
IMHO the watcher needs a notifier (HttpServiceWatcherdepends on an IFailureNotifier implementation). Let's make this decision clear to the container:
public class HttpServiceWatcher { private IFailureNotifier notifier; public HttpServiceWatcher(IFailureNotifier notifier) { this.notifier = notifier; } public void StartWatching() { // should start a thread to ping the service // if (pingresult == Failed) // { notifier.Notify(); // } } public void StopWatching() { // stop thread } }
Now the Windsor Container (in fact the MicroKernel) knows that in order to create an HttpServiceWatcher instance, it needs an implementation of IFailureNotifier to supply.
Let's change our App class to configure the components
:public static void Main() { IWindsorContainer container = new WindsorContainer(); // Register the components container.AddComponent("httpservicewatcher", typeof(HttpServiceWatcher)); container.AddComponent("email.notifier", typeof(IFailureNotifier), typeof(EmailFailureNotifier)); container.AddComponent("alarm.notifier", typeof(IFailureNotifier), typeof(AlarmFailureNotifier)); container.AddComponent("form.component", typeof(Form1)); // Request the component to use it Form1 form = (Form1) container[typeof(Form1)]; ...
We should also make the Form1 request the HttpServiceWatcher. Now there is a trick here: if we change the constructor generated by Visual Studio designer, making a non-parameterless constructor, the designer will complain. So let's just create another constructor:
public class Form1 : System.Windows.Forms.Form { private readonly HttpServiceWatcher serviceWatcher; private System.ComponentModel.Container components = null; public Form1() { InitializeComponent(); } public Form1(HttpServiceWatcher serviceWatcher) : this() { this.serviceWatcher = serviceWatcher; } ...
Now you are invited to run the application, debug it and see how the "wiring" process happens. Add two buttons to the form so you can call serviceWatcher.StartWatching() and serviceWatcher.StopWatching().
Proceed with Using the configuration file.