Monthly Archives: May 2007

CrossAppDomainSingleton – Update

I forgot a couple of very essential things in my last post about a singleton that lives across appdomains.

When accessing a remote object using remoting, like I did with the singleton implementation, the remoting system obtains a lease for the object. The lease period is implemented in the MarshalByRefObject class through a method called InitializeLifeTimeService(). A singleton like the one we wanted to achieve needs to live forever, therefor you need to override the InitializeLifeTimeService() method and always return null. Returning null means that it should live forever (more details can be at http://msdn.microsoft.com/msdnmag/issues/03/12/LeaseManager/default.aspx)

1
2
3
4
5
6
7
8
9
10
11
12
13
    /// <summary>
    /// Override of lifetime service initialization.
    /// 
    /// The reason for overriding is to have this singleton live forever
    /// </summary>
    /// <returns>object for the lease period - in our case always null</returns>
    public override object InitializeLifetimeService()
    {
      // We want this singleton to live forever
      // In order to have the lease across appdomains live forever,
      // we return null.
      return null;
    }

In addition I’ve made it all threadsafe. So look at the attachment for this post instead..

On a second note; if you for instance expose an event in your singleton and any subscribers to that event exists in another AppDomain, you might want to keep in mind that you should probably inherit from MarshalByRefObject and override the IntializeLifeTimeService() method and return null there as well. Otherwize you might end up having a broken lease in the delegate added to the singleton.

The updated C# file for this can be found here.

Silverlight – very very very slow

I’ve read several places, both blogs and forums that people are so impressed by the speed of Silverlight..
I must regretably say that I’m not one of them. I hope this is just the case with the Alpha version of Silverlight 1.1 and that the performance will increase when it reaches release.

I applied texturemapping to my 3D engine yesterday and the FPS (Frames Per Second) went from about 30 FPS to 2-3 FPS. I can easily switch back and forth and see the difference clearly. The test object I have have about 400 faces visible at every given time, and the area they are filling is not big. As I mentioned, I hope this is just the case with the early Alpha release, or even better, I hope it is a problem in my code.

I will be investigating this further and post my findings.

A bug in Silverlight 1.1 Alpha Polygon Visual?

I’m working on my 3D engine still and all of a sudden all my polygons didn’t show up on the screen.
After some hours of debugging I figured out what the problem was. At one point yesterday I removed some casts I had for setting the points for the polygons. The Point class in Silverlight has X and Y as double but the rendering engine does not seem to manage this at all. I have to cast it to int before I use them and remove all decimals.

This clearly can’t be “by design”.

Server down today and maybe tomorrow

Due to some electrical work in my house, I had to kill my servers today and might have to do it for some hours tomorrow as well.. 🙁     For some strange reason my UPS does not have 8 hours of power in it.

It’s all back up now at least.. 

Finally the long awaited extension to my family arrived today

During the pregnancy we’ve been presented with a lot of different dates, ranging from late april till late may. Finally today we got the extension to the family we’ve been waiting for. His name is Herman and weighed in at a remarkable 4395 grams and had a length of 51 cm. Based upon the last dates presented by the doctor, he arrived exactly one week too late. His mother struggled for some 8 hours to bring him into this world and did a remarkable job (even though I was thrown one or two interesting sentences.:) )

Life is beatiful!

Based upon previous experience with getting kids, it will now take me two years or so before I write my next blog..   NOT…  🙂    I’m too excited about Silverlight these days to not end up writing a post now and then.. 

 

3D in Silverlight 1.1 Alpha

Being a game developer at heart, my first instincts whenever a technology comes out that have visuals to it is to figure out a way to create some cool 3D stuff..

Silverlight proved to be a challenge doing this seeing that Microsoft dropped all of the subset of XAML that has to do with 3D. But fear not, it has the polygon visual…    That means we can do a lot of fun.

I’ve published an early version of my 3D engine at the following URL :
http://www.dolittle.com/Silverlight/3D/TestPage.html

In order to run it, you need the Silverlight 1.1 Alpha runtime, it can be
downloaded at the following location :
http://msdn.microsoft.com/vstudio/eula.aspx?id=e2c1a44f-0b5c-face-28c8-08a26f2e0b3c

It should look something like this :

Silverlight 3D - First Shot 

I will be publishing the source for the solution when I have it looking a bit better.

On to making texturemapping a reality … 🙂

 UPDATE, 13th of June 2007 :
SourceCode is out. Read more about it at : http://www.dolittle.com/blogs/einar/archive/2007/06/13/balder-3d-engine-for-silverlight-source-code-is-out.aspx

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:windowsmicrosoft.netframeworkv2.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..

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;

}

returnnull;

}

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.FullN ame, 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 entire C# sample file from here

private static AppDomain GetAppDomain(string friendlyName) 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;
}
{
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;
}