What do you call a Singleton that does not prevent more than one instance from being created? I call it confused. That is precisely what I was upon discovering the default effect of WellKnownObjectMode.Singleton in .NET Remoting. As I worked around this default behavior I realized my discovery and solution would be useful to others. This post discusses the differences between Singleton and Monostate, proves why a Remoting Singleton is Monostate by default, and shows how to design a true Singleton for .NET Remoting. It also includes several unit-testing tricks along the way!
What do you do when you need to develop an interface to the same state? For example, your customer wants message exchange amongst clients of the application. Your first story goes something like this:
As a user I want to create text messages in the system and retrieve them again at will.
It seems clear that you will need a message type in your domain. Let us examine what its test fixture might look like.
using System;
using Domain;
using NUnit.Framework;
namespace Test.Domain
{
[TestFixture]
public class MessageFixture
{
#region Data Members
private IMessage itsMessage;
#endregion
[SetUp]
protected virtual void SetUp()
{
itsMessage = new Message(Guid.NewGuid(), "simple message");
}
[Test]
public void ConstructorShouldReturnMessageInstance()
{
Assert.IsInstanceOfType(typeof(Message), itsMessage);
}
As a byproduct of making the tests pass you finish the Message type. After returning to the story it seems clear that you will need a message repository - some place to store and retrieve messages.
using System;
using System.Collections;
using System.Runtime.Remoting.Lifetime;
using Common;
using Domain;
using NUnit.Framework;
namespace Test.Domain
{
[TestFixture]
public class MessageRepositoryFixture
{
#region Data Members
private IMessageRepository itsMessageRepository;
private Message itsMessage;
#endregion
[SetUp]
protected virtual void SetUp()
{
itsMessageRepository = new MessageRepository();
itsMessage = new Message(Guid.NewGuid(), "simple message");
}
[Test]
public void ConstructorWithoutParametersShouldReturnInstanceOfMessageRepository()
{
Assert.IsInstanceOfType(typeof(MessageRepository), new MessageRepository());
}
Again you complete the MessageRepository as a result of making the tests pass. Now that Message and MessageRepository exist you complete the story by using them in your system. You modify the user interface so that messages can be created and retrieved - and put that under test of course! But during acceptance testing a bug is discovered. It seems that after a period system inactivity exceptions are being thrown on the server from within MessageRepository. All your tests are passing - yet you can reproduce the exceptions on your development server. You resolve to write tests that exactly mimic the server deployment. Your application server hosts MessageRepository using .NET Remoting so you know a remoting service is needed.
You write both the fixture and the remoting service and as soon as you run a test that waits the same amount of time reported by your users - BAM! - you reproduce the exception. So what in the world is happening here? Before answering that question we should define and contrast Singleton and Monostate.
The Singleton design pattern is used to restrict instantiation of a type to a single instance. This is typically done by making the parameterless constructor private and exposing an Instance property. The Monostate design pattern restricts instantiation of type state to a single instance. This is typically done by making type state static and exposing accessors to state; constructors are public thus multiple instances may exist.
Both design patterns can be used to share state. They differ in that Singleton creation and destruction is not well-controlled whereas they are with Monostate. The Singleton is purportedy the most widely known of all design patterns - but Monostate flies low under the radar. That is unfortunate because it is quite useful as design patterns go. Many of the problems that arise from the use of Singleton can be avoided by use of Monostate.
We are now ready to understand why exceptions are being thrown within MessageRepository. It is due to .NET Remoting lifetime management of types registered as WellKnownObjectMode.Singleton. .NET Remoting uses a lease-based lifetime service: a lease is obtained when an object proxy is marshaled and renewed on every call through that proxy. As soon as there are no outstanding leases for an object instance - and no sponsors renew its lifetime - the object is garbage collected. The default for initial object lifetime is five (5) minutes and two (2) minutes thereafter. Thus any object registered as a Remoting Singleton will be garbage collected after five minutes of inactivity. That is why exceptions are being thrown! If you look closely at the MessageRepository constructor it throws an exception if its storage is not empty. This can only happen if a prior instance had been created.
if (theStorage.Count > 0)
throw new ApplicationException("An instance of MessageRepository has already been created." +
Environment.NewLine + "MessageRepository is intended to be hosted as a Singleton.");There is a solution. The lifetime service can be overriden by implementing MarshalByRefObject.InitializeLifetimeService. What you want to do in this method is returns an ILease object set to your desired initial, renewal, and sponsorship lifetimes. To get true Singleton behavior from .NET Remoting return zero (0) for initial lifetime - indicating an infinite lease.
Want to see what a real MarshalByRef Singleton looks like? Want to see how to host .NET Remoting within NUnit? Download the solution.
I leave you with one final tip...
In C# the finalizer uses the destructor syntax from C++. But remember this is the Common Language Runtime so it all gets parsed into MSIL. If you reflect into any object that implements a finalizer - even one written in C# - you find a Finalize method. Thus if you want to cover an object finalizer use reflection to invoke the Finalize method.
GC.SuppressFinalize(objectReference);
new Reflection().InvokeMethod(objectReference, "Finalize", null);The attached solution includes several techniques that we at ThoughtShapes employ to deliver the best possible service to our customers. One of them is Dependency Injection. This technique is at the core of testing code, reducing dependencies, and identifying seams within existing code. My next post will use dependency injection while demonstrating how to dispatch UI messages to an alternate sink during testing. In the meantime I hope this post has stirred some thoughts in your mind. I would very much like to hear them if you feel like sharing.
| Attachment | Size |
|---|---|
| singleton_lifetime.zip | 963.27 KB |
Comments
I'd like to point something out that might not be obvious to all readers. In Rjae's post you'll notice that he doesn't provide the code for the types he mentions (Message and MessageRepository) but instead provides the test fixtures that test these types. This is a very important, conscious (and I believe totally correct) decision he must have made and it emphasizes what we practice: The tests are the most important thing in the code. I say "must have made" in the previous sentence because I normally don't like making assumptions about another's thoughts, but I do know the way Rjae thinks in regards to this area and I also know his thoughts totally jibe with mine.
One perspective in particular to try to grab hold of is to look at the test fixture method names. When I read the test method names I gain an instant understanding of what the behavior of the CUT (Class Under Test) is. I therefore gain a much quicker understanding of the class than I would if I was looking at the actual code for the class. I'm not sure how obvious this is to readers, so I think it's worth mentioning. Even if you're only developing a class library for a client, it's a good idea to ship all the tests with the code. I know that if I hire someone to create a library for me I'd be giddy if they give me all the tests. (This is really not true, but only because I'd expect all the tests in advance--since that would be part of the contract with the library writer. If I didn't have such a contract, then I'd be giddy.)
And, as I've said before and will say again, this is why the tests serve as the documentation.
I should add that there is another way for a MarshalByRefObject to indicate infinite lifetime. Return null from InitializeLifetimeService as in:
public override object InitializeLifetimeService() { return null; }Unless your object needs control over sponsor and renewal lifetime it is best to use this approach.
The Monostate design pattern takes the general form:
public class ClassName { private static int theStaticState = 0; public virtual int StaticState { get { return theStaticState; } set { theStaticState = value; } } }The type itself is not limited to a single instance but its state is. In this way the benefits of polymorphism are protected (no pun intended ;-).