How do I share a Singleton between AppDomains?

J

Joseph Geretz

I've built a singleton class which I want to share among different
application clients (code below). I've confirmed that the singleton class
works properly within a single client. Although the application can acquire
multiple references to the class, all references point to a single class
instance. However, when loaded by different applications, each application
gets its own class instance. How can I extend the nature of this singleton
so that it provides one instance and only one instance regardless of the
number of clients / application domains which request it?

Thanks immensely for your advice!

- Joseph Geretz -

Singleton class coded according to the recommendation of:
http://www.yoda.arachsys.com/csharp/singleton.html

public sealed class Singleton
{
// The Singleton instance - the only instance ever created.
private static readonly Singleton m_Instance = new Singleton();

private static readonly string m_InstanceID =
Guid.NewGuid().ToString();

// Explicit static constructor to tell C# compiler not
// to mark type as beforefieldinit. Do not remove!
static Singleton()
{
// m_Instance could be created inside this static
// constructor, or simultaneous to its static
// definition as defined above. no difference.
}

// Private instance constructor prevents clients
// from creating their own instance. Only way to
// obtain an instance is to request the static
// Instance which hands out the single instance
// to all clients.
private Singleton()
{
}

public static Singleton Instance
{
get
{
return m_Instance;
}
}

public string InstanceID
{
get
{
return m_InstanceID;
}
}
 
J

Joseph Geretz

Thanks Vadim,

I was able to set this up using remoting. I've done something which I
haven't seen documented. I'd appreciate feedback from anyone who is familiar
with singletons and remoting.

In order to remove the client application from the whole issue of remoting,
I've split the solution into two classes; Singleton and SingleCore. The
client application simply instantiates an instance of Singleton in the
conventional manner. In its constructor, the Singleton class creates a
server instance of SingleCore, or if the server instance already exists
acquires a reference to it. (The restriction of SingleCore to a single
instance is handled by the Remoting infrastructure.)

(Note that the constructor for SingleCore is internal. Although references
to SingleCore can be handed out by Singleton, only Singleton can actually
create the instance of of SingleCore, this restricting SingleCore to a
single instance per machine.)

I've included my code below and I'd appreciate any feedback. I've tested the
class instance across multiple applications and I see that I get the same
GUID back in every single application which is an improvement on my first
attempt at a classic singleton which returned the same GUID for each
instance per AppID, but not across multiple AppID's. I will proceed with
this design. My primary lines of investigation at this point are:

1. How safe is this class for calls from multiple client applications? My
needs in terms of performance are modest, I simply need to accommodate
synchronous calls from a couple of end-user applications on the same
workstation. My main concern is to ensure that method calls will be
completed atomically before the next method call will be accommodated. I
guess I could use locking to enforece this, but i'm not sure whether I need
to do this, or whether the framewor will intrinsically 'single thread' calls
into the server class instance.

2. Will clients be able to receive Events from the SingleCore class? This is
the whole point of what I'm trying to do. I want a method call from
Application A to raise an Event in Application B to inform it that
Application A has performed a certain unit of work. Again, will there be any
concern due to multiple clients receiving events from the same class
instance across multiple AppDomains?

I've included my code below. Thanks for any advice which you can offer.

- Joseph Geretz -

----------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace Singleton
{
[ComVisible(true)]
public sealed class Singleton
{
private SingleCore m_Instance;
private TcpChannel m_Channel;

public Singleton()
{
try
{
// If the server class is already registered, this will trip
// an exception and we'll simply proceed to acquire
// an instance of the instance which is already available.
m_Channel = new TcpChannel(13101);

ChannelServices.RegisterChannel(m_Channel, false);
RemotingConfiguration.RegisterWellKnownServiceType
(typeof(SingleCore),
"Singleton.SingleCore",
WellKnownObjectMode.Singleton);

m_Instance =
(SingleCore)Activator.GetObject(typeof(SingleCore),
"tcp://localhost:13101/Singleton.SingleCore");
}
catch
{
m_Instance =
(SingleCore)Activator.GetObject(typeof(SingleCore),
"tcp://localhost:13101/Singleton.SingleCore");

}
}

public SingleCore Instance
{
get
{
return m_Instance;
}
}
}
}

SingleCore:
----------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;

namespace Singleton
{
public class SingleCore : MarshalByRefObject
{
private string m_InstanceID;

internal SingleCore()
{
m_InstanceID = Guid.NewGuid().ToString();
}

public string InstanceID
{
get
{
return m_InstanceID;
}
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top