Blog'A'Little

Just another C# guy

Cross AppDomain Singleton

PS: There is an addition to this post that you can find here 

One thing that I find a bit inconvient from time to time is the lack of shared memory between appdomains. Today I figured I had to find a way of doing this, so I created a CrossAppDomainSingleton class that has it's implementation and data shared between AppDomains.

The solution we want is that the singleton class is created in a given AppDomain and in all other AppDomains we get a transparent proxy to that singleton. 

In order to do this we need to have the ability to enumerate through existing AppDomains in order to create an instance in the correct AppDomain (at least I found this to be cool way of doing it). I came across a thread on microsoft.public.dotnet.framework.clr that gave me a good solution (http://groups.google.com/group/microsoft.public.dotnet.framework.clr/browse_frm/thread/dba9c445ad8d5c3/9df14bf0af393c28?lnk=st&q=enumerate+appdomain+group%3Amicrosoft.public.dot%20net.*&rnum=5#9df14bf0af393c28)

You need to add a reference to the mscoree.tlb which is situated in the .net directory (c:\windows\microsoft.net\framework\v2.0.50727). When you add a reference to it you'll get an Interop.mscoree.dll added to your output directory. You will have to have this alongside your deployment if you're going to use this in a solution.

With my modifications, we get a method that finds a AppDomain based upon the friendly name. If it doesn't find it, it returns null..


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  private static AppDomain GetAppDomain(string friendlyName)
{
IntPtr enumHandle = IntPtr.Zero;
mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
try
{
host.EnumDomains(out enumHandle);

object domain = null;
while (true)
{
host.NextDomain(enumHandle, out domain);
if (domain == null)
{
break;
}
AppDomain appDomain = (AppDomain)domain;
if( appDomain.FriendlyName.Equals(friendlyName) )
{
return appDomain;
}
}
}
finally
{
host.CloseEnum(enumHandle);
Marshal.ReleaseComObject(host);
host = null;
}
return null;
}

The full implementation of the class is then :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 public class CrossAppDomainSingleton<T> : MarshalByRefObject where T:new()
{
private static readonly string AppDomainName = "Singleton AppDomain";
private static T _instance;

private static AppDomain GetAppDomain(string friendlyName)
{
IntPtr enumHandle = IntPtr.Zero;
mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
try
{
host.EnumDomains(out enumHandle);

object domain = null;
while (true)
{
host.NextDomain(enumHandle, out domain);
if (domain == null)
{
break;
}
AppDomain appDomain = (AppDomain)domain;
if( appDomain.FriendlyName.Equals(friendlyName) )
{
return appDomain;
}
}
}
finally
{
host.CloseEnum(enumHandle);
Marshal.ReleaseComObject(host);
host = null;
}
return null;
}


public static T Instance
{
get
{
if (null == _instance)
{
AppDomain appDomain = GetAppDomain(AppDomainName);
if (null == appDomain)
{
appDomain = AppDomain.CreateDomain(AppDomainName);
}
Type type = typeof(T);
T instance = (T)appDomain.GetData(type.FullName);
if (null == instance)
{
instance = (T)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
appDomain.SetData(type.FullName, instance);
}
_instance = instance; }

return _instance;
}
}
}

This class is not thread safe, so that bit needs to be added..

To use the class you do the following :

1
2
3
4
5
6
7
8
 public class MySingleton : CrossAppDomainSingleton<MySingleton>
{

public void HelloWorld()
{
Console.WriteLine("Hello world from '" + AppDomain.CurrentDomain.FriendlyName + " (" + AppDomain.CurrentDomain.Id + ")'");
}
}

Look at the attachment to this blog for the entire C# sample file!!

 

kick it on DotNetKicks.com kick it on GameDevKicks.com

Comments

Marcin Buciora said:

COOL!!!!

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 11, 2008 12:22

Einar Ingebrigtsen said:

Thanks. I've working on a new version that will work with the compact framework as well. Involves quite a bit magic. :)  

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 11, 2008 10:48

Tini said:

Thank you soo much for this! really helpful.

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 23, 2008 10:39

Einar Ingebrigtsen said:

No problem. I'm glad it turned out helpful for you.

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 24, 2008 10:07

Delf said:

Thanks a lot for this generic singleton class. Now I should be able to get access to my singletons over App domains. This point is really appreciated when applications using plugins/modules that use application singletons.

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 25, 2008 11:48

Einar Ingebrigtsen said:

Glad to be of any assistance. You should also look at the update post for this :

www.dolittle.com/.../crossappdomainsingleton-update.aspx

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 25, 2008 5:42

CrossAppDomainSingleton - Update - Blog'A'Little said:

Pingback from  CrossAppDomainSingleton - Update - Blog&#39;A&#39;Little

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 25, 2008 6:14

Frederick Chapleau weBlog on IT. said:

The basic way to do a Plugin Framework, is to use a AppDomains, because you can Load &amp; Unload AppDomains

kick it on DotNetKicks.com kick it on GameDevKicks.com
# oktober 15, 2008 11:19

molly said:

htMlKq viTwQ937Baww5mLp1oWxu

kick it on DotNetKicks.com kick it on GameDevKicks.com
# august 18, 2009 4:24

payday loans said:

Your website is very interesting. I enjoyed your website a lot. Thank you.

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 2, 2010 4:49

PetrKunkAlpinist1977 said:

Da haste dir aber viel m�he gegeben

Den Eiger in 2,47 Stunden zu besteigen w�hre wohl vor 70Jahren nicht moeglich gewesen

Respekt Ueli Steck!

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 3, 2010 1:33

http://uxjqzz.com/ said:

VSQmbDHa

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 26, 2010 11:54

Jonathan Dickinson said:

I have figured out another solution that doesn't need MSCOREE interop. You might want to look at it. jonathan.dickinsons.co.za/.../cross-domain-singleton-in-c

kick it on DotNetKicks.com kick it on GameDevKicks.com
# november 2, 2010 12:29

http://ivpsqt.com/ said:

ytuJhh

kick it on DotNetKicks.com kick it on GameDevKicks.com
# januar 31, 2011 12:14

devvvy said:

Hello

If I set some secret/sensitive information in AppDomain ...

AppDomain.CurrentDomain.SetData(SOME_SECRET_KEY, PrivateKey)

How can I protect it from third party dll loaded on demand? For example, in our application which hosts third party dll,

MaliciousLib = Assembly.LoadFrom(DllPath);

oService = MaliciousLib.CreateInstance("xxxx.xxxx.xxxx");

ISomeService Service = (ISomeService) oService;

Service.DoSomeWork(...);

Here, MaliciousLib can also access AppDomain and retrieves secret key.

I'm considering loading third party dll's into separate app domain (In which case they can't have access to the main AppDomain right...? In which case, next logical question - how 3rd party lib communicates back to main assembly... while it can't access main assembly's AppDomain variables, perhaps "function call return" would suffice ...)Cake

But I just done some testing, User dll methods can still access AppDomain.CurrentDomain!

oSecret = AppDomain.CurrentDomain.GetData("KEY1");

Many articles discuss theories surrounding AppDomain, how one process can host multiple AppDomain and disaster occurring in one won't bring down the whole process - but really? Thought that's .NET v1 behavior - from v2 on disaster in one AppDomain will bring down the whole process. Also, regarding Get/SetData from security perspective, there's nothing on Google. From my experiment, there isn't any security control on Get/SetData!Cake

So really how to protect main app from loaded third party components? Any suggestion?

kick it on DotNetKicks.com kick it on GameDevKicks.com
# mars 3, 2011 10:17

Kamren said:

Hahahaha. I’m not too birhgt today. Great post!

kick it on DotNetKicks.com kick it on GameDevKicks.com
# mai 4, 2011 7:52

Jeremy Child said:

4 years on and still useful. Thankyou!

kick it on DotNetKicks.com kick it on GameDevKicks.com
# juli 12, 2011 3:26
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Design downloaded from Free Templates - your source for free web templates