2014-09-29 2 views
1

Я пытаюсь сделать следующее:Загрузка сборка байтового массива в новый AppDomain бросает исключение FileNotFound

  • Скачать байтовый массив, который содержит сборку, что мне нужно выполнить.
  • Загрузить объект из этого узла в новом домене приложения и выполнить метод объекта

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

public object Execute(byte[] agentCode) 
    { 
     var app = AppDomain.CreateDomain("MonitoringProxy", AppDomain.CurrentDomain.Evidence, new AppDomainSetup {ApplicationBase = AppDomain.CurrentDomain.BaseDirectory}, new PermissionSet(PermissionState.Unrestricted)); 
     app.AssemblyResolve += AppOnAssemblyResolve; 
     var assembly = app.Load(agentCode); 

кодовую базу умирает последней строки со следующим сообщением:

Дополнительная информация: не удалось загрузить файл или сборку «Alertera.AgentProxy, Version = 1.0.0.0, Культура = нейтральная, PublicKeyToken = null 'или одна из ее зависимостей. Система не может найти указанный файл.

Никакой код никогда не попадает на функцию AppOnAssemblyResolve. Что интересно, так это то, что он правильно прочитал название сборки. Кроме того, сборка Alertera.AgentProxy не имеет внешних зависимостей, кроме System и Newtonsoft.Json. Тем не менее, Newtsoft.Json был внедрен в него как ресурс, поэтому его не нужно загружать отдельно.

Любые указатели? Использование .NET 2 для максимальной совместимости

+0

Я думаю, что это не удается, потому что 'Load' загружает сборку в текущий домен (который не имеет обработчика сборки разрешаемыми), в соответствии с Документами:«Этот метод следует использовать только для загрузки сборки в текущий домен приложения. Этот метод предоставляется в качестве удобства для вызывающих абонентов взаимодействия, которые не могут вызвать статический метод Assembly.Load. Чтобы загружать сборки в другие области приложений, используйте такой метод, как CreateInstanceAndUnwrap. " –

+0

Я видел эти комментарии. Думаю, я не уверен, как это сделать. Я вызываю CreateInstanceAndUnwrap, но после того, как сборка загружена в домен приложения. У CreateInstanceAndUnwrap нет способа загрузить массив байтов. Можете ли вы поделиться образцами кода, чтобы правильно загрузить сборку в новый домен приложения? – Igorek

+0

Не знаете об этом, но поможет ли Fuslogvw.exe? – RenniePet

ответ

2

Возможно, использование обратного вызова в домене приложения для перехода к контексту вновь созданного домена приложения позволит вам успешно загрузить? Что-то вроде этого ...

public object Execute(byte[] assemblyBytes) 
    { 
     AppDomain domainWithAsm = AsmLoad.Execute(assemblyBytes); 
     .... 
    } 

    [Serializable] 
    public class AsmLoad 
    { 
     public byte[] AsmData; 

     public void LoadAsm() 
     { 
      Assembly.Load(AsmData); 
      Console.WriteLine("Loaded into: " + AppDomain.CurrentDomain.FriendlyName); 
     } 

     public static AppDomain Execute(byte[] assemblyBytes) 
     { 
      AsmLoad asmLoad = new AsmLoad() { AsmData = assemblyBytes }; 
      var app = AppDomain.CreateDomain("MonitoringProxy", AppDomain.CurrentDomain.Evidence, new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory }, new PermissionSet(PermissionState.Unrestricted)); 
      app.DoCallBack(new CrossAppDomainDelegate(asmLoad.LoadAsm)); 
      return app; 
     } 
    } 

EDIT:

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

class Program 
{ 
    static void Main(string[] args) 
    { 
     var assemblyBytes = File.ReadAllBytes(@"C:\dev\Newtonsoft.Json.dll"); 

     // load an unload the same assembly 5 times 
     for (int i = 0; i < 5; i++) 
     { 
      var assemblyContainer = AssemblyContainer.LoadAssembly(assemblyBytes, true); 
      var assemblyName = assemblyContainer.AssemblyName; 

      assemblyContainer.Unload(); 
     } 

     Console.ReadKey(); 
    } 
}  

[Serializable] 
public class AssemblyContainer 
{ 
    public byte[] AssemblyData { get; set; } 
    public bool ReflectionOnly { get; set; } 
    private AppDomain Container { get; set; } 
    public AssemblyName AssemblyName { get; set; } 

    /// <summary> 
    /// Unload the domain containing the assembly 
    /// </summary> 
    public void Unload() 
    { 
     AppDomain.Unload(Container); 
    } 

    /// <summary> 
    /// Load the assembly 
    /// </summary> 
    /// <remarks>This will be executed</remarks> 
    public void LoadAssembly() 
    {     
     var assembly = ReflectionOnly ? Assembly.ReflectionOnlyLoad(AssemblyData) : Assembly.Load(AssemblyData); 
     AssemblyName = assembly.GetName(); 

     // set data to pick up from the main app domain 
     Container.SetData("AssemblyData", AssemblyName); 
    } 

    /// <summary> 
    /// Load the assembly into another domain 
    /// </summary> 
    /// <param name="assemblyBytes"></param> 
    /// <param name="reflectionOnly"></param> 
    /// <returns></returns> 
    public static AssemblyContainer LoadAssembly(byte[] assemblyBytes, bool reflectionOnly = false) 
    { 
     var containerAppDomain = AppDomain.CreateDomain(
      "AssemblyContainer", 
      AppDomain.CurrentDomain.Evidence, 
      new AppDomainSetup 
      { 
       ApplicationBase = AppDomain.CurrentDomain.BaseDirectory 
      }, 
      new PermissionSet(PermissionState.Unrestricted)); 

     AssemblyContainer assemblyContainer = new AssemblyContainer() 
     { 
      AssemblyData = assemblyBytes, 
      ReflectionOnly = reflectionOnly, 
      Container = containerAppDomain 
     }; 

     containerAppDomain.DoCallBack(new CrossAppDomainDelegate(assemblyContainer.LoadAssembly)); 

     // collect data from the other app domain 
     assemblyContainer.AssemblyName = (AssemblyName)containerAppDomain.GetData("AssemblyData"); 
     return assemblyContainer; 
    }    
}  
+0

Наконец-то обдумал эту проблему (в итоге первоначально загружая сборки в текущий домен). Мне пришлось настроить ваш код, чтобы использовать делегат AssemblyResolve вместо прямого Assembly.Load, но в остальном он работает как шарм. Благодаря! – Igorek

+0

Привет, вы можете поделиться «измененной» версией - решение не работает для меня. – MajkeloDev

+0

@MajkeloDev, когда вы говорите «это не работает», можете ли вы быть более конкретным? Есть ли ошибка? – steve16351