samedi 7 novembre 2020

Cannot return value from class that inherits MarshalByRefObject

I use load / unload assembly to get all types then create instances from that type. I debug, the variable "result" in the Reflect method of the AssemblyReflectionProxy class has a value but after the return line of that method is an error, hope everyone help me, I want to copy some values in the instance created from the type of the assembly that I have loaded.

Error Infomation

"Could not load file or assembly 'BeyConsRevitProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."

StackTrace

" at BeyConsConsole.Reflections.AssemblyReflectionProxy.Reflect[TResult](Func2 func) in D:\Github\BeyConsPlugin\BeyConsConsole\Reflections\AssemblyReflectionProxy.cs:line 39\r\n at BeyConsConsole.Reflections.AssemblyReflectionManager.Reflect[TResult](String assemblyPath, Func2 func) in D:\Github\BeyConsPlugin\BeyConsConsole\Reflections\AssemblyReflectionManager.cs:line 59\r\n at BeyConsConsole.Program.Main() in D:\Github\BeyConsPlugin\BeyConsConsole\Program.cs:line 27"

Error Image

[https://ift.tt/3n0r4Ow]

[https://ift.tt/38osmPw]

[https://ift.tt/36aB0ya]

IAssemblyReflectionProxy interface

public interface IAssemblyReflectionProxy
{
    void LoadAssembly(string assemblyPath);
    TResult Reflect<TResult>(Func<Assembly, TResult> func);
}

AssemblyReflectionProxy class

public class AssemblyReflectionProxy : MarshalByRefObject, IAssemblyReflectionProxy
{

    #region Fields
    private string assemblyPath;
    #endregion

    #region Methods
    public void LoadAssembly(string assemblyPath)
    {
        try
        {
            this.assemblyPath = assemblyPath;
            Assembly.ReflectionOnlyLoadFrom(assemblyPath);
        }
        catch { }
    }
    public TResult Reflect<TResult>(Func<Assembly, TResult> func)
    {
        DirectoryInfo directory = new FileInfo(assemblyPath).Directory;
        Assembly ResolveEventHandler(object s, ResolveEventArgs e) { return OnReflectionOnlyResolve(e, directory); }
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveEventHandler;
        Assembly assembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(a => a.Location.CompareTo(assemblyPath) == 0);
        TResult result = func(assembly);
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= ResolveEventHandler;
        return result;
    }
    private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
    {
        Assembly loadedAssembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault(asm => string.Equals(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase));
        if (null != loadedAssembly) return loadedAssembly;
        AssemblyName assemblyName = new AssemblyName(args.Name);
        string dependentAssemblyFilename = Path.Combine(directory.FullName, assemblyName.Name + ".dll");
        if (File.Exists(dependentAssemblyFilename))
        {
            return Assembly.ReflectionOnlyLoadFrom(dependentAssemblyFilename);
        }
        return Assembly.ReflectionOnlyLoad(args.Name);
    } 
    #endregion

}  

AssemblyReflectionManager class

public class AssemblyReflectionManager : IDisposable
{

    #region Fields
    private readonly Dictionary<string, AppDomain> mapDomains = new Dictionary<string, AppDomain>();
    private readonly Dictionary<string, AppDomain> loadedAssemblies = new Dictionary<string, AppDomain>();
    private readonly Dictionary<string, AssemblyReflectionProxy> proxies = new Dictionary<string, AssemblyReflectionProxy>();
    #endregion

    #region Methods
    public bool LoadAssembly(string assemblyPath, string domainName)
    {
        if (!File.Exists(assemblyPath)) return false;
        if (loadedAssemblies.ContainsKey(assemblyPath)) return false;

        AppDomain appDomain;
        if (mapDomains.ContainsKey(domainName))
        {
            appDomain = mapDomains[domainName];
        }
        else
        {
            appDomain = CreateChildDomain(AppDomain.CurrentDomain, domainName);
            mapDomains[domainName] = appDomain;
        }

        try
        {
            Type proxyType = typeof(AssemblyReflectionProxy);
            if (null != proxyType.Assembly)
            {
                var proxy = (AssemblyReflectionProxy)appDomain.CreateInstanceFrom(proxyType.Assembly.Location, proxyType.FullName).Unwrap();
                proxy.LoadAssembly(assemblyPath);
                loadedAssemblies[assemblyPath] = appDomain;
                proxies[assemblyPath] = proxy;
                return true;
            }
        }
        catch { }
        return false;
    }
    public TResult Reflect<TResult>(string assemblyPath, Func<Assembly, TResult> func)
    {
        if (loadedAssemblies.ContainsKey(assemblyPath) && proxies.ContainsKey(assemblyPath))
        {
            return proxies[assemblyPath].Reflect(func);
        }
        return default;
    }
    public bool UnloadAssembly(string assemblyPath)
    {
        if (!File.Exists(assemblyPath)) return false;
        if (loadedAssemblies.ContainsKey(assemblyPath) && proxies.ContainsKey(assemblyPath))
        {
            AppDomain appDomain = loadedAssemblies[assemblyPath];
            int count = loadedAssemblies.Values.Count(a => a == appDomain);
            if (count != 1) return false;
            try
            {
                mapDomains.Remove(appDomain.FriendlyName);
                AppDomain.Unload(appDomain);
                loadedAssemblies.Remove(assemblyPath);
                proxies.Remove(assemblyPath);
                return true;
            }
            catch { }
        }
        return false;
    }
    public bool UnloadDomain(string domainName)
    {
        if (string.IsNullOrEmpty(domainName)) return false;

        if (mapDomains.ContainsKey(domainName))
        {
            try
            {
                var appDomain = mapDomains[domainName];
                var assemblies = new List<string>();
                foreach (var kvp in loadedAssemblies)
                {
                    if (kvp.Value == appDomain) assemblies.Add(kvp.Key);
                }
                foreach (var assemblyName in assemblies)
                {
                    loadedAssemblies.Remove(assemblyName);
                    proxies.Remove(assemblyName);
                }
                mapDomains.Remove(domainName);
                AppDomain.Unload(appDomain);
                return true;
            }
            catch { }
        }
        return false;
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~AssemblyReflectionManager()
    {
        Dispose(false);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            foreach (var appDomain in mapDomains.Values)
            {
                AppDomain.Unload(appDomain);
            }
            loadedAssemblies.Clear();
            proxies.Clear();
            mapDomains.Clear();
        }
    }
    private AppDomain CreateChildDomain(AppDomain parentDomain, string domainName)
    {
        Evidence evidence = new Evidence(parentDomain.Evidence);
        AppDomainSetup setup = parentDomain.SetupInformation;
        return AppDomain.CreateDomain(domainName, evidence, setup);
    } 
    #endregion

}

Test

public class Program
{
    public static void Main()
    {
        try
        {
            string assemblyPath = @"D:\Github\BeyConsPlugin\BeyConsProject\bin\x64\Debug\BeyConsRevitProject.dll";
            AssemblyReflectionManager manager = new AssemblyReflectionManager();
            if (manager.LoadAssembly(assemblyPath, Guid.NewGuid().ToString()))
            {
                var result = manager.Reflect(assemblyPath, (a) =>
                {
                    Type[] types = new Type[] { };
                    types = a.GetTypes();
                    return types;
                });
            }
        }
        catch (Exception exception)
        {
            string str = exception.ToString();
        }
        Console.ReadKey();
    }
}

Debug before line 39 still gets types, after line 39, throw an exception

[4] https://i.stack.imgur.com/CgyEQ.png





Aucun commentaire:

Enregistrer un commentaire