Have you ever needed some kind of “master switch” in your application – i.e. some central place to flick a bool, resulting is changed behavior in numerous places?
Recently, we got the requirement that our application could function in two modes: active and passive. In active mode, the application must work like usual, whereas in passive mode, the app must not do anything to the outside world.
In our app, doing stuff to the outside world can be two things:
- Writing stuff to a bunch of external SCADA systems.
- Publishing status messages via NServiceBus.
which means that in order to implement passive mode, we need to avoid doing these two things.
Now, since everything in our app is wired by Windsor, and Windsor supports the nifty decorator pattern, implementing this “master switch” was a breeze!
The master switch
First, we implemented something like this to capture the switch itself:
1 2 3 4 |
public class MasterSwitch { public bool IsActive { get; set; } } |
which is registered like this:
1 |
container.Register(Component.For<MasterSwitch>().Lifestyle.Singleton); |
Note th at the switch is a singleton, thus allowing all other services to have the same instance injected. Note also that concurrency is not an issue in our system – if MasterSwitch was to be used e.g. in an ASP.NET MVC application, it would have had a couple of locks in there or something similar.
Intercepting writes to external systems
All external hardware communication goes through an implementation of this interface:
1 2 3 4 5 |
public interface IExternalStuff { void Write(string name, object value); object Read(string name); } |
so in order to abort all writes when we’re in passive mode, we added a new implementation of IExternalStuff that looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class ExternalStuffWithMasterSwitch : IExternalStuff { readonly MasterSwitch masterSwitch; readonly IExternalStuff externalStuff; public ExternalStuffWithMasterSwitch(MasterSwitch masterSwitch, IExternalStuff externalStuff) { this.masterSwitch = masterSwitch; this.externalStuff = externalStuff; } public object Read(string name) { return externalStuff.Read(name); } public void Write(string name, object value) { if (!masterSwitch.IsMaster) return; externalStuff.Write(name, value); } } |
Note how ExternalStuffWithMasterSwitch depends on IExternalStuff – this is where Windsor gets really cool, because if I remember to register my components in the following order:
1 2 3 4 5 |
container.Register(Component.For<IExternalStuff>() .ImplementedBy<ExternalStuffWithMasterSwitch>() .Lifestyle.Transient, Component.For<IExternalStuff>() .Instance(new ExternalStuffViaSomeWrappedThirdPartyComponent())); |
then Windsor is smart enough to resolve the ExternalStuffWithMasterSwitch supplying the next available implementation of IExternalStuff, instead of entering a cycle.
Thus, we have cancelled all writes through IExternalStuff in our entire application with a few lines of extra code.
Avoiding publishing status messages
First, we needed som way to tell if a message was a status message, which was pretty easy – now all our status messages “implement” this marker interface which in turn implements IMessage from NServiceBus:
1 |
public interface IStatusMessage : IMessage {} |
So, in order to “swallow” all published status messages when we’re in passive mode, we implemented this decorator to IBus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class BusDecoratorThatSwallowsPublishedStatusMessages : IBus { readonly MasterSwitch masterSwitch; readonly IBus bus; public BusDecoratorThatSwallowsPublishedStatusMessages(MasterSwitch masterSwitch, IBus bus) { this.masterSwitch = masterSwitch; this.bus = bus; } // (...) quite a few methods up here public void Publish<T>(T message) where T : IMessage { if (!masterSwitch.IsActive && message is IStatusMessage) return; bus.Publish(message); } } |
which must be registered before NServiceBus’ own IBus gets registered:
1 2 3 4 5 6 7 |
container.Register(Component.For<IBus>() .ImplementedBy<BusDecoratorThatSwallowsPublishedStatusMessages>() .Lifestyle.Transient); NServiceBus.Configure.With() .CastleWindsorBuilder(container) // (...) |
I think this is a really cool example on how wiring everything with an IoC container provides some cool hooks in an application, allowing you to modify behavior in an extremely agile and non-intrusive manner.
There’s good reason against mixing component registration and decorator configuration. Service overrides define which imlementation is used by a component that needs it. Registration order defines a default implementation for a service, which is a rather different concern. So, Castle’s smartness “to resolve the ExternalStuffWithMasterSwitch supplying the next available implementation” is rather error-prone.
Yeah, I understand why you think that “Castle’s smartness” is rather error-prone… as always, when you have the option of either being explicit about stuff, or letting stuff happen by convention, it’s important to take into account whether the chosen solution will violate POLA… and whether a given solution is a violation, depends very much on whether this style of convention-based programming is a well-understood and accepted among your team members.
Thanks for the comment, what the heck… great name, btw 🙂