Using an absolute path in probing privatePath

according to MSDN:

You can use the element only in machine configuration or publisher policy files that also redirect the assembly version. ... If you are supplying a code base hint for an assembly that is not strong-named, the hint must point to the application base or a subdirectory of the application base directory.

You probably tried to apply in in app.config?

and

The directories specified in privatePath must be subdirectories of the application base directory.


Use an AssemblyResolver instead in this situation.

Here's some code I cribbed partly from another question and modified for our own use. Unlike the linked code, this one resolves the application execution folder, which was something I haven't seen in many other examples. Feel free to excise that and stick in your own absolute path if necessary.

One advantage of the assembly resolver is that if you have mixed versions of your dlls, and want to load the dll from the target folder, not the one that happens to be with the app, then this works whereas the config file method doesn't.

I have that problem because our app ships with a small utility that is an app upgrader, and it often needs to reference newer versions of the dlls than the original app. (The upgrader gets updated, then the upgrader updates the main app. If they both look at the same dlls, bad things can happen.)

public static class AssemblyResolver
{
    internal static void Hook(params string[] folders)
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // Check if the requested assembly is part of the loaded assemblies
            var loadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name);
            if (loadedAssembly != null)
                return loadedAssembly;

            // This resolver is called when a loaded control tries to load a generated XmlSerializer - We need to discard it.
            // http://connect.microsoft.com/VisualStudio/feedback/details/88566/bindingfailure-an-assembly-failed-to-load-while-using-xmlserialization

            var n = new AssemblyName(args.Name);

            if (n.Name.EndsWith(".xmlserializers", StringComparison.OrdinalIgnoreCase))
                return null;

            // http://stackoverflow.com/questions/4368201/appdomain-currentdomain-assemblyresolve-asking-for-a-appname-resources-assembl

            if (n.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
                return null;

            string assy = null;
            // Get execution folder to use as base folder
            var rootFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)??"";

            // Find the corresponding assembly file
            foreach (var dir in folders)
            {
                assy = new[] { "*.dll", "*.exe" }.SelectMany(g => Directory.EnumerateFiles(Path.Combine(rootFolder,dir), g)).FirstOrDefault(f =>
                {
                    try
                    {
                        return n.Name.Equals(AssemblyName.GetAssemblyName(f).Name,
                            StringComparison.OrdinalIgnoreCase);
                    }
                    catch (BadImageFormatException)
                    {
                        return false; /* Bypass assembly is not a .net exe */
                    }
                    catch (Exception ex)
                    {
                        // Logging etc here
                        throw;
                    }
                });

                if (assy != null)
                    return Assembly.LoadFrom(assy);
            }

            // More logging for failure here
            return null;
        };
    }
}

Invoke this early on providing a list of paths to use for assembly resolving

AssemblyResolver.Hook("upglib","myOtherFolder");

Tags:

C#