Posts Tagged ‘typeloading’

Type Resolving

Thursday, January 31st, 2008

When you write an application for the .net framework it’s very common to separate the various parts into visual studio projects which will be represented in separate assemblies (dll or exes) after compiling them.

This is usually done like that so other applications can link those assemblies without needing to include a whole stack of drivers for a little piece of logic (you know, reusability, reliability, blablabla…) So you end up with two or more applications/dlls depending the same dll.

Nothing special until here.

Deployment

So what happens when the user, like in my case, puts the executable out of directory with the shared dlls?

Exactly, the program cannot be started and fails with a TypeLoadException because it could not load all its dependencies.

The .net way to solve this is by putting the shared dlls into the global assembly cache (GAC). However, this requires the dlls to be signed with a key and will cause a lot of work if you have sub-dependencies because every signed component needs all its references to be signed as well.

And if you sign all the dlls you change the signature of them and break any existing client/dll. That will cause a big redeployment just because somebody wasn’t happy with a simple link and wanted to put the whole exe to his desktop (and we have lots of dlls, we explicitly decided not to spam the GAC and had some other reasons as well)

But of course there will be a solution for this I thought.

Assembly specific configuration is normally defined by a .config file which has the same name like the assembly itself. E.g.

MyApp.exe
MyApp.exe.config

Loads the xml configuration and applies it to the dll/exe while it gets loaded. With “probing” you can specify further directories where the class loader should look for the required types if they could not be found in the expected location. Anyway, you cannot know where the shared directory is located when you write the config file but I let that for now.

<configuration>
<runtime>
<assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1">
	<probing privatepath="dirA;dirB"></probing>
</assemblybinding>
</runtime>
</configuration>

So I referred to my shared dll directory but guess what, it didn’t work! msdn tells me that those probing paths must not be above the application’s root path. Ha! how nice..

Fortunately, I have a remoting server running to which my client apps need to connect anyway so I could implement a way cooler solution.

TypeLoadException

When the client application could not resolve the dependency it calls some handlers which let the developer handle such cases before quitting.
You can register yourself for such cases with

AppDomain.CurrentDomain.AssemblyResolve +=
	new ResolveEventHandler( DoResolve );

and handle it in a method with this signature

System.Reflection.Assembly DoResolve(
	object sender, ResolveEventArgs args)

My plan

When my event handler method gets called, I call my remoting server and ask
“Hey mate, I need an assembly called ‘args.Name’. You have such a thing?”
“Sure. It’s located in MyCompany\Shared\MyCompany.foo.bar.dll”

When I have the the path information I can do something like

System.Reflection.Assembly.LoadFile( path );

and my client will load that assembly and finds the needed type information in it.

Thus in the end it looks like

private Assembly DoResolve(
	object sender, ResolveEventArgs args )
{
  String path = myServer.GetAssemblyLocation( args.Name );
 
  if( path == null )
	return null;
  else
	return System.Reflection.Assembly.LoadFile( path );
}

In the end the only dll left in the GAC is a dll where the resolving is implemented. Thus the only thing the client must do is calling helperDllInGac.AddAutoResolving() in the first line of its main() and a handler for type loading errors in the current AppDomain will be registered and all dlls will be resolved dynamically.

With this mechanism you can move all executables to any place and they will find their dependencies as long as the service is running. This may not be necessary in your case, but if you have lots of little tools it gets very annoying when you need to sign and register almost every dll because you cannot be sure that executable will be in the same directory.

Instead of returning a path you could also provide a byte array representing the assembly in the servers resolving method and gain even more flexibility. However, depending on what you are doing this it not a real solution and may make things even more complicated and slow.

Notes

Stack

AddAutoResolving() must be called *before* any external types appear while the stack gets built.
E.g.

void main( String[] args )
{
	new Helper().AddAutoResolving();
	MyExternalType t;
	new MyGUIApp();
}

will fail because while the CLR builds the method stack it has no idea about the unknown type yet, calls the handlers but there aren’t any registered yet and the app fails anyway.

LoadFile

LoadFile is just for people who know what they are doing. If you need those anti-dll-hell-features like versioning and policy don’t use it.

Where did my type go?

Saturday, November 3rd, 2007

With the .Net 2.0 release in 2005 it was finally possible to use generics in c#. That dramatically reduced the code complexity and made programming in that language a little bit nicer again. The classes stayed flexible and elegant and despite the generics support was not even close to the magic it has in other languages it was better than nothing. I started using it immediately.

“wow… generics are so cool!”

A few weeks ago I wanted to provide my generic class, lets call it HandlePool<>, in a remoting application. The first problem I run into was that there is no way to access generics when the inner type is unknown.

HandlePool{} h = remotedObject.GetHandlePool();

wont work. Also

HandlePool{Object} h = remotedObject.GetHandlePool();

will fail on runtime while casting the object because of the underlying and fundamental problem that e.g. List<String> may not be casted into a List<Object>. Generics used in a context where you don’t know the types explicitly will cause huge problems because you cannot refer to a “generic base type”. The only possible way is accessing it over an interface (which must not be generic, otherwise the problem starts again).

“Well, generics has it’s drawbacks”

Because the generic class does just provide a handful operations I decided to wrap it by copying its interface to a normal object so I could access it with:

remotedObject.HandlePool.GetHandleByName();

However, when accessing the remoted object like that, the client receives a TypeLoadException.
Soon I noticed that the exception occurred while deserializing the remoted object. After stumbling around a bit, I discovered that during the object’s deserialization the client’s app domain found the type HandlePool<LoggingHandle> in the deserialization context but could not resolve the type because it was not defined in the app domain yet of course. How could it be?

By writing HandlePool<LoggingHandle> in my servers object I defined the new type HandlePool<LoggingHandle> on the fly in my server’s AppDomain. That was unknown to the clients because until then nobody defined that type there. However, I can’t do it in my client anyway because I don’t know yet which types I will receive from the server in future.

“Argh!”

As always in those “Damn! I’m fucked and have to rewrite everything” situations, I glanced at the reflection API. Until that day it always provided a solution for last-minute-design hacks.
So I hoped to be able to invoke the type somehow by generics and avoid the TypeLoadException

The old reflection API provided this way:

Type t; 
 
//this implicitly requires an empty constructor 
 
Object o = t.GetConstructor(
       new Type[]{} ).Invoke( new Object[]{} );

“Nice”

I tried but it still didn’t work. TypeLoadException… mhh…

Haide, it’s .Net, hacks are allowed and everywhere. So I continued trying…

After that I came up with the idea: building the type HandlePool<LoggingHandle> during runtime by reflection. Checking the reflection API.. and..
uh.. No way to specify a generic type. This was the first time I realized that maybe generics is not that nice if used across several modules and its unknown with which specific type you have to deal with.
But after a few minutes I found the MakeGenericType command. From msdn:

Substitutes the elements of an array of types for the type parameters of the current generic type definition and returns a Type object representing the resulting constructed type.

“Wohooo!”

So I need the type information of the type “inside” the generic and I will be able to add the correct type definition into my AppDomain which allows me to deserialize the remoted generic object.

“So how to get that type now?”

If I do something like remotedObject.HandlePool.GetGenericType(), I wont come very far because HandlePool has to be resolved first and that will result in an exception.

Thus I need a helper object with which I somehow can get the type by do something like

helper.GetGenericType()

And then I have the “inside” type in my app domain. The assembly where this type is defined is has to be around as well, but I ignore that now.

So when I have the generic type in my app domain, I can do something like

Type innerType = helper.GetGenericType(); 
 
//building generic type
Type newConcreteGenericType = Type.MakeGenericType(
       new Type[]{ innerType } ); 
 
//now deserialization works
remotedObject.GetHandlePool();

And it worked!

“Uhuu, reflection saved me another time”

Of course compared to static generic definitions this is incredible slow, but I used it just once in an init method and thus for me it was okay. (Note: I skipped the exception handling)

Wasn’t that easy. I will pay attention when using generics the next time. Sometimes they cause more problems than they actually solve.