Posted by: Cirilo Meggiolaro | 12/14/2008

Tip of the day #61 – Resolving assembly dependencies failures when loading assemblies for reflection only

Let’s assume the following scenario:

  1. You want to load an assembly using one of the methods available under the System.Reflection namespace for reflection only. It means that you just want to check what is inside it;
  2. You want to explore modules, types and or methods;
  3. Your assembly code depends on objects available in a referenced assembly;
  4. Once you are loading only your target assembly, the CLR cannot resolve the references by itself and an exception will be thrown.

How to…

When the CLR cannot resolve an assembly reference one event named ReflectionOnlyAssemblyResolve is raised. The event is available under the AppDomain class and the signature is available below:

Assembly ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args);

So, the first step to workaround that scenario is to add an event handler to your application to catch this event like the following code snippet describes:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(MyEventHandler);

The second step is to create your event handler method that will retrieve an instance of the referenced assembly. You may have up to three options to retrieve the assembly reference:

  • Retrieve from the same location than the main assembly;
  • Retrieve from the global assembly cache (GAC);
  • Displays a open file dialog to allow the user to select the correct assembly.

The following code snippet displays all of them:

private Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly dep = null;
    bool hasFound = false;

    try
    {
        /// Try to load the dependency from the same location
        /// than the original assembly. We need to keep track
        /// about the source directory.

        dep = Assembly.ReflectionOnlyLoadFrom(_sourceDirectory + args.Name.Substring(0, args.Name.IndexOf(‘,’)) + “.dll”);

        if (dep != null) hasFound = true;
    }
    catch (System.IO.FileNotFoundException)
    {
        hasFound = false;
    }

    if (!hasFound)
    {
        try
        {
            /// Try to load from the GAC.
            dep = Assembly.ReflectionOnlyLoad(args.Name);

            if (dep != null) hasFound = true;
        }
        catch (System.IO.FileLoadException)
        {
            hasFound = false;
        }
    }

    if (!hasFound)
    {
        try
        {
            /// One other option is to display an open dialog form
            /// so the user can select the correct assembly location.
            dlgOpenFile.Title = “Select the referenced assembly “ + args.Name;

            if (dlgOpenFile.ShowDialog() != DialogResult.Cancel)
                dep = Assembly.ReflectionOnlyLoadFrom(dlgOpenFile.FileName);
        }
        catch (Exception ex)
        {
            MessageBox.Show(“The following error has occurred: “ + ex.Message);
        }
    }

    return dep;
}

Advertisements

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

Categories

%d bloggers like this: