Работа с AppDomain для временной загрузки сборок

C Robinson спросил: 14 ноября 2017 в 07:09 в: c#

Я создаю инструмент WPF, который будет анализировать посредством сборки сборки целевого приложения.

Я до сих пор использовал Assembly.Load и т. д. для загрузки целевых сборок. Это нормально, за исключением того, что у него есть пара ограничений: я хочу иметь возможность перестроить целевое приложение и "обновить" инструмент для повторного анализа вновь собранных сборок. В настоящее время это не будет работать, потому что сборки блокируются при нагрузке и не освобождаются до выхода инструмента. Это также исключает повторную загрузку вновь созданных сборок.

Я полагаю, что могу создать временный домен приложений, загрузить в него сборки, выполнить отражение, которое я хочу сделать, а затем выгрузить домен.

Проблема в том, что я не могу заставить ее работать. Я перепробовал множество вариантов и получил такие результаты, как:

  • Загрузка в текущий домен приложения, а не в тот, который я явно создал
  • Ошибка загрузки запрошенной сборки
  • Ошибка загрузки сборки инструмента (?)

Например, следуйте приведенному ниже предложению: Создайте собственный домен приложения и добавьте в него сборки

Я создал SimpleAssemblyLoader следующим образом:

public class SimpleAssemblyLoader : MarshalByRefObject
{
    public Assembly Load(string path)
    {
        ValidatePath(path);        return Assembly.Load(path);
    }    public Assembly LoadFrom(string path)
    {
        ValidatePath(path);        return Assembly.LoadFrom(path);
    }    public Assembly UnsafeLoadFrom(string path)
    {
        ValidatePath(path);        return Assembly.UnsafeLoadFrom(path);
    }    private void ValidatePath(string path)
    {
        if (path == null) throw new ArgumentNullException(nameof(path));
        if (!System.IO.File.Exists(path))
            throw new ArgumentException($"path \"{path}\" does not exist");
    }
}

... и таким образом использовал его в вызывающем методе:

    private static AppDomain MakeDomain(string name, string targetPath, string toolPath)
    {
        var appDomain =
            AppDomain.CreateDomain(name, AppDomain.CurrentDomain.Evidence, new AppDomainSetup
                {
                    ApplicationBase = targetPath,
                    PrivateBinPath = toolPath,
                    LoaderOptimization = LoaderOptimization.MultiDomainHost
                },
                new PermissionSet(PermissionState.Unrestricted));
        return appDomain;
    }    /// <summary>
    /// 
    /// </summary>
    /// <param name="targetPath">Location of assemblies to analyze</param>
    /// <param name="toolPath">Location of this tool</param>
    /// <param name="file">Filename of assembly to analyze</param>
    /// <returns></returns>
    public string[] Test(string targetPath, string toolPath, string file)
    {
        var dom = MakeDomain("TestDomain", targetPath, toolPath);
        var assemblyLoader = (SimpleAssemblyLoader)dom.CreateInstanceAndUnwrap(typeof(SimpleAssemblyLoader).Assembly.FullName, typeof(SimpleAssemblyLoader).FullName);        var path = Path.Combine(targetPath, file);        var assembly = assemblyLoader.LoadFrom(path);        var types = assembly.GetTypes();        List<string> methods = new List<string>();        foreach (var type in types)
        {
            foreach (var method in type.GetMethods(BindingFlags.Instance|BindingFlags.Public))
            {
                methods.Add(method.Name);
            }
        }        AppDomain.Unload(dom);        return methods.ToArray();
    }

... приложение инструмента запускается, но оно не может создать экземпляр SimpleAssemblyLoader, сообщая об исключении "Файл не найден", связанный со сборкой инструмента - очевидно, пытается загрузить сборку инструмента в новый домен (?).

Что я делаю не так и как это исправить?

0 ответов