Thursday, April 30, 2015

AppDomain is refusing to find dll dependencies

Hello again.

I had some health problems and less free time to work on this issue, which is why it took me this long for this :

I tried to apply suggestions from Mike Danes, however i still get the same result : FileNotFoundException.

When i use VS to check the operations step by step, i can see the program found the right dll and loaded it, however it seems it is unable to find it's dependencies.

Here is the Fusion Log i got that has weird paths :

=== Pre-bind state information ===
LOG: DisplayName = WAM.Modules.AlertScanner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: E:\Projects\VS\Warframe Activity Manager\WAM.Desktop\bin\Debug\WAM.Desktop.exe.config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/WAM.Modules.AlertScanner.DLL.
LOG: Attempting download of new URL file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/WAM.Modules.AlertScanner/WAM.Modules.AlertScanner.DLL.
LOG: Attempting download of new URL file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/WAM.Modules.AlertScanner.EXE.
LOG: Attempting download of new URL file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/WAM.Modules.AlertScanner/WAM.Modules.AlertScanner.EXE.

The first wrong thing is the he first attempt to download the assemblt file in file:///E:/Projects/VS/Warframe Activity Manager/WAM.Desktop/bin/Debug/WAM.Modules.AlertScanner.DLL. The path is the application path, not the path to the modules fodler which should be http://file/E:\Projects\VS\Warframe Activity Manager\Modules\Debug\AlertScanner. The same applies to the next attempts.

I have added a class file in the WAM.Common.Core.dll assembly :

using System;
using System.IO;
using System.Reflection;

namespace WAM.Common.Core
{
    public class PluginAssemblyLoader : MarshalByRefObject
    {
        public Assembly GetAssembly(String path)
        {
            try
            {
                return Assembly.LoadFile(Path.GetFileNameWithoutExtension(path));
            }
            catch (Exception)
            {
                return null;
                // throw new InvalidOperationException(ex);
            }
        }
    }
}

And the plugin manager code looks as this :

public Plugin(String path, Type moduleType)
        {
            if (String.IsNullOrEmpty(path))
                throw new ArgumentException("Plugin : path is null or empty");
            if (moduleType == null)
                throw new ArgumentException("Plugin : moduleType is null");

            _moduleType = moduleType;
            AppDomainSetup s = new AppDomainSetup();
            s.ApplicationName = Path.GetFileNameWithoutExtension(path);
            s.ApplicationBase = Path.GetDirectoryName(path);
            s.CachePath = Path.Combine(Path.GetDirectoryName(path), "cache" + Path.DirectorySeparatorChar);
            s.ShadowCopyFiles = "true";
            s.ShadowCopyDirectories = Path.Combine(Path.GetDirectoryName(path), "sc" + Path.DirectorySeparatorChar);
            _domain = AppDomain.CreateDomain(Path.GetFileNameWithoutExtension(path), null, s);

            Type type = typeof(PluginAssemblyLoader);
            PluginAssemblyLoader loader = (PluginAssemblyLoader)_domain.CreateInstanceAndUnwrap(
                type.Assembly.FullName,
                type.FullName);
            _assembly = loader.GetAssembly(path);
            
            var assemblies = _domain.GetAssemblies();
            foreach (var ass in assemblies)
            {
                try
                {
                    foreach (IList<Type> t in ass.GetTypes())
                    {
                        foreach (var tpe in t)
                            if (_moduleType.IsAssignableFrom(tpe))
                                _modules.Add(tpe);
                    }    
                }
                catch (Exception)
                {
                    break;
                }
            }
        }

Another thing that bothers me is that catch should catch the exceptions thrown by Assembly.LoadFile() and only return null, but i still get it once PluginAssemblyLoader.GetAssembly() returns. Is that normal?


No comments:

Post a Comment