Hugoware

The product of a web developer with a little too much caffeine

Woes With External Assemblies

leave a comment »

In all my years developing with .NET I haven’t ever had a situation that I needed to load an external library into my code at runtime. Normally, I simply add the reference to my project and I’m on my way. As it turns out it can be slightly tricky if you’re new to it.

I’m working on a project right now that is broken up into several pieces, one of which is a shared library that other external libraries use, specifically to inherit from a base class used by yet another part of the application. The shared class is actually referenced by each of the projects but one part of the application loads the assemblies in at runtime.

To summarize…

  1. SharedLibrary is referenced by MainApplication
  2. SharedLibrary is referenced by ExternalLibrary
  3. ExternalLibrary is loaded dynamically by MainApplication
  4. ExternalLibrary has classes that inherit from classes in SharedLibrary
  5. MainApplication needs to cast classes in ExternalLibrary into base class types found in SharedLibrary

So to illustrate what happens imagine two classes the abstract class ParentClass and the inheriting class ChildClass. This code made sense to me when I first typed it in but the results surprised me.

//create the instance
string path = @"d:\projects\libraries\exampleLibrary.dll";
object child = AppDomain.CurrentDomain
    .CreateInstanceFromAndUnwrap(path, "ExampleLibrary.ChildClass");
Type type = child.GetType();

//the details about the class
Console.WriteLine("Class is: {0}", child);
Console.WriteLine("Type Name: {0}", type.FullName);
Console.WriteLine("Load : {0}", type.Assembly.FullName);
Console.WriteLine("Ref  : {0}", typeof(ParentClass).Assembly.FullName);
Console.WriteLine("Is ChildClass  : {0}", child is ChildClass);
Console.WriteLine("Is ParentClass : {0}", child is ChildClass);
Console.WriteLine("Casting : {0}", child as ParentClass);

//the results
//Class is: ExampleLibrary.ChildClass
//Type Name: ExampleLibrary.ChildClass
//Load : ExampleLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
//Ref  : ExampleLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
//Is ChildClass  : False
//Is ParentClass : False
//Casting : <-- which is null

What the heck? Admittedly, I don’t know why this fails – If I had to guess it would have something to do… well… we will discuss it in a moment…

I ended up with the following solution which worked exactly the way I had hoped.

//load the assembly manually
string path = @"d:\projects\libraries\exampleLibrary.dll";
byte[] bytes = File.ReadAllBytes(path);
AppDomain.CurrentDomain.Load(bytes);

//create the instance
object child = AppDomain.CurrentDomain
    .CreateInstanceAndUnwrap("ExampleLibrary", "ExampleLibrary.ChildClass");
Type type = child.GetType();

//the details about the class
Console.WriteLine("Class is: {0}", child);
Console.WriteLine("Type Name: {0}", type.FullName);
Console.WriteLine("Load : {0}", type.Assembly.FullName);
Console.WriteLine("Ref  : {0}", typeof(ParentClass).Assembly.FullName);
Console.WriteLine("Is ChildClass  : {0}", child is ChildClass);
Console.WriteLine("Is ParentClass : {0}", child is ChildClass);
Console.WriteLine("Casting : {0}", child as ParentClass);

//the results
//Class is: ExampleLibrary.ChildClass
//Type Name: ExampleLibrary.ChildClass
//Load : ExampleLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
//Ref  : ExampleLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
//Is ChildClass  : True
//Is ParentClass : True
//Casting : ExampleLibrary.ChildClass

Hmm… Not what I was expecting…

Even still, the code might be working – but one thing I always tell other developers is “that’s great your code is working – now, why is it working?”

After poking around for a bit I noticed something that really should have been obvious from the beginning. Take a look at this code and you’ll see where I’m headed…

Console.WriteLine("Load : {0}", type.Assembly.Location);
Console.WriteLine("Ref  : {0}", typeof(ParentClass).Assembly.Location);

//Load : d:\projects\libraries\exampleLibrary.dll
//Ref  : d:\projects\application\bin\debug\exampleLibrary.dll

Oh… so maybe not exactly the same type after all… 😐

I suspect that by loading the bytes in directly took the whole ‘location’ thing out of picture. Of course, I need to read up on this some more before I’m positive but if any of you genius developers out there can confirm my theory then it would be greatly appreciated.

Advertisements

Written by hugoware

March 4, 2010 at 12:29 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: