2017-10-24 3 views
1

현재 응용 프로그램 도메인 기본 폴더가 아닌 폴더에서 어셈블리를로드하려고합니다. 로드하려는 어셈블리 중 일부는 이미 기본 버전의 응용 프로그램 도메인에 이전 버전으로로드되어 있습니다. 이것을 실행하기 위해 다음 코드를 발견했습니다. 새로운로드 어셈블리 폴더 C : \ 종피 \이미로드 된 모든 참조가있는 어셈블리로드

코드의 저자는 내가 찾을 수 없음 파일이나 의존성을 얻을 언급 한 바와 같이
class Program 
{ 
    static void Main(string[] args) 
    { 
     AppDomainSetup domaininfo = new AppDomainSetup(); 
     domaininfo.ApplicationBase = @"c:\testa\"; 
     Evidence adevidence = AppDomain.CurrentDomain.Evidence; 
     AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo); 

     Type type = typeof(Proxy); 
     var value = (Proxy)domain.CreateInstanceAndUnwrap(
      type.Assembly.FullName, 
      type.FullName); 

     var assembly = value.GetAssembly(args[0]); 
     // AppDomain.Unload(domain); 
    } 
} 

public class Proxy : MarshalByRefObject 
{ 
    public Assembly GetAssembly(string assemblyPath) 
    { 
     try 
     { 
      return Assembly.LoadFile(assemblyPath); 
     } 
     catch (Exception) 
     { 
      return null; 
      // throw new InvalidOperationException(ex); 
     } 
    } 
} 

How to Load an Assembly to AppDomain with all references recursively?

. 어떻게이 문제를 처리 할 수 ​​있을까요? 어떤 생각?

답변

0

.NET Framework를 사용하면 Application Domain에로드하는 동안 어셈블리 확인 코드를 완전히 제어 할 수 있습니다. AppDomain.AssemblyResolve 이벤트에 첨부 된 이벤트 핸들러를 사용하면됩니다. 이벤트 처리기의 역할은 어셈블리를로드하고 Assembly 인스턴스를 반환하는 것입니다. 로드 된 어셈블리가 실행 준비가되어있는 한 그것이 완료되는 방식은 구현 자의 몫입니다. 예를 들어 새 어셈블리를 즉시 생성하고로드 한 후에 참조를 반환 할 수 있습니다. 이 이벤트는 주 모듈, 위성 어셈블리, 리소스 어셈블리 및 모든 종속성에 대해 발생하므로 thet 메서드를 사용하면 문제가 해결 될 것으로 보인다.

static void Main(string[] args) 
{ 
    AppDomainSetup domaininfo = new AppDomainSetup(); 
    domaininfo.ApplicationBase = @"c:\testa\"; 
    Evidence adevidence = AppDomain.CurrentDomain.Evidence; 
    AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo); 
    AssemblyResolver resolver = new AssemblyResolver(); 
    domain.Assembly += resolver.Resolve; 

    Type type = typeof(Proxy); 
    var value = (Proxy)domain.CreateInstanceAndUnwrap(
     type.Assembly.FullName, 
     type.FullName); 

    var assembly = value.GetAssembly(args[0]); 
    // AppDomain.Unload(domain); 
} 

이러한 데이터는 메인 프로그램 어셈블리 구성 파일로부터 검색된다 생산 하드 코딩 어셈블리 데이터보다 복잡한 AssemblyResolver 클래스 해결 인스턴스 메소드의 구현 : 이하

public Assembly Resolve(object sender, ResolveEventArgs e) 
{ 

    System.Diagnostics.Debug.WriteLine("AssemblyResolve event for: {0}\t\tRequestingAssembly {1}", e.Name, e.RequestingAssembly); 

    switch(e.Name) 
    { 
     case "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=aed0ab2de30e5e00": 
      return LoadAssembly(e); 
     case "System.Data.SQLite.EF6, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139": 
      return LoadAssembly(e); 
     case "BlueTechZone.Sqlite.EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7741556173e269b9": 
      string codeBase = CodeBase + _SubDirectory + "System.Data.SQLite.EF6.dll"; 
      var ef6SQLite = Assembly.LoadFrom(codeBase); 
      return LoadAssembly(e, new String[] { "SQLite.Interop.dll" }); 
     case "System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139": 
      return LoadAssembly(e, new String[] { "SQLite.Interop.dll" }); 
     default: 
      return null; 
    } 
} 

사용되는 코드 응용 프로그램의 나머지 부분이 도메인에로드되기 전에 실행될 도메인과 동일한 도메인에 리졸버를 연결합니다. APP_CONFIG_FILE은 응용 프로그램 도메인에서 사용하는 구성 파일의 경로를 설정하는 데 사용됩니다.

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"E:\src\**\<assembly name>.dll.config"); 

AssemblyResolver = new AssemblyResolver(); 
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.Resolve; 
+0

나는 리졸버를 테스트했다. 하지만 제 경우에는 해고되지 않았습니다. – Michael

0

프로그램의 흐름을 변경했기 때문에 문제가 해결되었습니다.

먼저 현재 디렉토리의 dll을 c : \ testa 디렉토리로 복사합니다. 기존 파일을 덮어 쓰지 않습니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     /* Copy files from current folder to c:\testa\ */ 

     AppDomainSetup domaininfo = new AppDomainSetup(); 
     domaininfo.ApplicationBase = @"c:\testa\"; 
     domaininfo.PrivateBinPath = @"c:\testa\"; 
     Evidence adevidence = AppDomain.CurrentDomain.Evidence; 
     AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo); 

     Type type = typeof(Proxy); 
     var value = (Proxy)domain.CreateInstanceAndUnwrap(
      type.Assembly.FullName, 
      type.FullName); 

     var assembly = value.Run(() => { /* My Program */}); 

    } 
} 

public class Proxy : MarshalByRefObject 
{ 
    public void GetAssembly(Action a) 
    { 
     a(); 
    } 
} 

그래서 나는 새로운 응용 프로그램 도메인에서 프로그램을 실행하고 모든 조립이 제대로로드 :

는 다음 나는 프로그램을 시작합니다.

관련 문제