ReflectionOnlyLoadFrom 후 어셈블리에서 형식을 가져올 수 없습니다.

Nov 07 2020

웹 사이트의 코드를 참조했습니다. http://codeproject.com Marius Bancila의 "Loading Assemblies from Anywhere to a New AppDomain"이라는 제목의 제목으로 첨부 된 그림과 같이 오류를 테스트했지만 현재는 해결 방법을 모르겠습니다. 도와주세요. 감사합니다.

링크 코드 https://www.codeproject.com/Articles/453778/Loading-Assemblies-from-Anywhere-into-a-New-AppDom#_articleTop

테스트

public class Program
{
    [STAThread]
    public static void Main()
    {
        var project = @"D:\Github\BeyConsPlugin\BeyConsProject\bin\x64\Debug\BeyConsRevitProject.dll";//Path to assembly
        var manager = new AssemblyReflectionManager();
        var success = manager.LoadAssembly(project, Guid.NewGuid().ToString());
        if (success)
        {
            var result = manager.Reflect(project, (a) =>
            {
                return a.GetTypes();
            });
            Console.WriteLine(string.Join("\n", result.Select(x => x.Name)));
        }            
        Console.ReadKey();
        manager.UnloadAssembly(project);
    }       
}

오류

답변

1 MickyD Nov 07 2020 at 10:16

어셈블리 해결 프로그램이 설정되지 않음

Marius의 코드에는 어떤 것과 다르게 AssemblyReflectionProxy호출하면 Assembly Resolver가 설정되지 않는다는 버그 가 있습니다.LoadAssemblyReflect<>

하위 앱 도메인이 생성되는 방법에 따라 어셈블리를로드 할 때 생성 중에 지정된 폴더에만 액세스 할 수 있습니다. 어셈블리 또는 해당 종속성에 대해 다른 곳에서 프로브를 어셈블리해야하는 경우 Assembly Resolver가 필요합니다. .NET이 도메인에 대한 어셈블리를 찾을 때 assemblie의 ReflectionOnlyAssemblyResolve이벤트에 지정된대로 처리기를 호출합니다 . 지정되지 않았거나 확인자가 어셈블리를 찾지 못하면 버블 링되고로드 실패 예외가 발생합니다.

다음에서 코드를 변경하는 것이 좋습니다.

public class AssemblyReflectionProxy : MarshalByRefObject
{
  private string _assemblyPath;

  public void LoadAssembly(String assemblyPath)
  {
     try
     {
        _assemblyPath = assemblyPath;
        Assembly.ReflectionOnlyLoadFrom(assemblyPath);
     }
     catch (FileNotFoundException)
     {
        // Continue loading assemblies even if an assembly 
        // cannot be loaded in the new AppDomain.
     }
  }

...에:

public class AssemblyReflectionProxy : MarshalByRefObject
{
  private string _assemblyPath;

  public void LoadAssembly(String assemblyPath)
  {
     try
     {
        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve // <---- add me
             += OnReflectionOnlyResolve; 

        _assemblyPath = assemblyPath;
        Assembly.ReflectionOnlyLoadFrom(assemblyPath);
     }
     catch (FileNotFoundException)
     {
        // Continue loading assemblies even if an assembly 
        // cannot be loaded in the new AppDomain.
     }
  }

Marius가 기반으로 한 Sacha의 원래 코드 에서 이것을 볼 수 있습니다 .

해결 경로에 대한 규정 추가

코드의 다른 문제는 둘 다 하나의 어셈블리를로드 할 때 모든 종속 어셈블리가 항상 그런 것은 아닐 수도있는 동일한 폴더에 있다고 가정한다는 것입니다.

AssemblyReflectionProxy프로브 할 경로 목록을 포함하도록 변경하십시오 .

public List<string> ResolvePaths { get; set; }

그런 다음 OnReflectionOnlyResolve를 다음과 비슷하게 수정합니다.

private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
{
     Assembly loadedAssembly =
         AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()
             .FirstOrDefault(
               asm => string.Equals(asm.FullName, args.Name,
                   StringComparison.OrdinalIgnoreCase));

     if (loadedAssembly != null)
     {
        return loadedAssembly;
     }

    foreach (var tryFolder in ResolvePaths)
    {
        var asmName = args.Name.Split(',');
        var assemblyPath = Path.Combine(tryFolder, asmName[0] + ".dll");

        if (!File.Exists(assemblyPath))
            return null;

         return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
    }
}

이름에 무엇이 있습니까?

두 기사 모두를 사용할 때 작은 글씨를 지적하는 것을 무시했습니다 ReflectionOnlyLoad. 하지만 사샤는 적어도 한 언급 그의 코드는 위해이었다 "코드 생성" 내가 도움이되지만 궁금해 할 수없는 그 자신과 두 기사 " Loading Assemblies... 새 응용 프로그램 도메인이에" 해석에 다소 아마도 있습니다 될 수 있습니다.

의 목적 ReflectionOnlyLoad은 그저 반성 입니다. 이 메서드를 통해 어셈블리를로드하면 그 안에있는 코드를 실행할 수 없습니다. 추가적으로 저를 포함한 대부분의 어셈블리 리플렉터 프로그래머들에게 처음에는 다소 놀랍습니다 ( 어셈블리에서 유형 을 "인스턴스화" 하려고 시도하기 때문에 호출 GetCustomAttributes도 실패 한다는 것입니다 ).

각 플러그인에 자체 앱 도메인이있는 자체 플러그인 시스템을 작성하는 경우 Assembly리플렉션 및로드 방법은 플러그인 시스템로드 파이프 라인의 여러 단계에 유용합니다.

  1. 첫 번째 패스- 플러그인이 유효한지 확인ReflectionOnlyLoad 하는 방법으로 사용 합니다. 이 단계에서 어떤 플러그인 코드도 실행할 수 없다는 것을 알고 안전하게 보안 검사를 실행하고 싶을 것입니다.
  2. 두 번째 패스-플러그인을 확인한 후 안전하게 Load/ LoadFrom조립하고 코드를 실행할 수 있습니다.