방법: MetadataLoadContext를 사용하여 어셈블리 콘텐츠 검사

개발자는 기본적으로 .NET의 리플렉션 API를 통해 주 실행 컨텍스트에 로드된 어셈블리의 콘텐츠를 검사할 수 있습니다. 그러나 예를 들어 다른 플랫폼 또는 프로세서 아키텍처에 대해 컴파일되었거나 참조 어셈블리이기 때문에 어셈블리를 실행 컨텍스트에 로드하지 못할 수도 있습니다. System.Reflection.MetadataLoadContext API를 사용하여 이러한 어셈블리를 로드하고 검사할 수 있습니다. MetadataLoadContext에 로드된 어셈블리는 메타데이터로만 처리됩니다. 즉, 어셈블리의 형식을 검사할 수 있지만 여기에 포함된 코드를 실행할 수는 없습니다. 주 실행 컨텍스트와 달리 MetadataLoadContext는 현재 디렉터리에서 종속성을 자동으로 로드하지 않고, 전달된 MetadataAssemblyResolver에서 제공하는 사용자 지정 바인딩 논리를 대신 사용합니다.

필수 조건

MetadataLoadContext를 사용하려면 MetadataLoadContext NuGet 패키지를 설치합니다. 모든 .NET Standard 2.0 규격 대상 프레임워크(예: .NET Core 2.0 또는 .NET Framework 4.6.1)에서 지원됩니다.

MetadataLoadContext용 MetadataAssemblyResolver 만들기

MetadataLoadContext를 만들려면 MetadataAssemblyResolver 인스턴스를 제공해야 합니다. 이를 제공하는 가장 간단한 방법은 지정된 어셈블리 경로 문자열 컬렉션에서 어셈블리를 확인하는 PathAssemblyResolver를 사용하는 것입니다. 이 컬렉션은 직접 검사하려는 어셈블리 외에도 필요한 모든 종속성을 포함해야 합니다. 예를 들어 외부 어셈블리에 있는 사용자 지정 특성을 읽으려면 해당 어셈블리를 포함해야 합니다. 그렇지 않으면 예외가 throw됩니다. 대부분의 경우 핵심 어셈블리, 즉 System.Object 같은 기본 제공 시스템 형식을 포함하는 어셈블리를 포함해야 합니다. 다음 코드에서는 검사된 어셈블리 및 현재 런타임의 핵심 어셈블리로 구성된 컬렉션을 사용하여 PathAssemblyResolver를 만드는 방법을 보여 줍니다.

var resolver = new PathAssemblyResolver(new string[] { "ExampleAssembly.dll", typeof(object).Assembly.Location });

모든 BCL 형식에 액세스해야 하는 경우 컬렉션에 모든 런타임 어셈블리를 포함할 수 있습니다. 다음 코드에서는 검사된 어셈블리 및 현재 런타임의 모든 어셈블리로 구성된 컬렉션을 사용하여 PathAssemblyResolver를 만드는 방법을 보여 줍니다.

// Get the array of runtime assemblies.
string[] runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");

// Create the list of assembly paths consisting of runtime assemblies and the inspected assembly.
var paths = new List<string>(runtimeAssemblies);
paths.Add("ExampleAssembly.dll");

// Create PathAssemblyResolver that can resolve assemblies using the created list.
var resolver = new PathAssemblyResolver(paths);

MetadataLoadContext 만들기

MetadataLoadContext를 만들려면 이전에 만든 MetadataAssemblyResolver를 첫 번째 매개 변수로 전달하고 핵심 어셈블리 이름을 두 번째 매개 변수로 전달하여 생성자 MetadataLoadContext(MetadataAssemblyResolver, String)를 호출합니다. 핵심 어셈블리 이름을 생략할 수 있습니다. 이 경우 생성자는 기본 이름인 "mscorlib", "System.webserver" 또는 "netstandard"를 사용합니다.

컨텍스트를 만든 후 LoadFromAssemblyPath와 같은 메서드를 사용하여 어셈블리를 로드할 수 있습니다. 코드 실행과 관련된 어셈블리를 제외하고 로드된 어셈블리에서 모든 리플렉션 API를 사용할 수 있습니다. GetCustomAttributes 메서드는 생성자 실행과 관련되므로 MetadataLoadContext에서 사용자 지정 특성을 검사해야 하는 경우 대신 GetCustomAttributesData 메서드를 사용합니다.

다음 코드 샘플에서는 MetadataLoadContext를 만들고, 어셈블리를 로드하고, 어셈블리 특성을 콘솔에 출력합니다.

var mlc = new MetadataLoadContext(resolver);

using (mlc)
{
    // Load assembly into MetadataLoadContext.
    Assembly assembly = mlc.LoadFromAssemblyPath("ExampleAssembly.dll");
    AssemblyName name = assembly.GetName();

    // Print assembly attribute information.
    Console.WriteLine($"{name.Name} has following attributes: ");

    foreach (CustomAttributeData attr in assembly.GetCustomAttributesData())
    {
        try
        {
            Console.WriteLine(attr.AttributeType);
        }
        catch (FileNotFoundException ex)
        {
            // We are missing the required dependency assembly.
            Console.WriteLine($"Error while getting attribute type: {ex.Message}");
        }
    }
}

같음 또는 할당 가능성을 위해 MetadataLoadContext의 형식을 테스트해야 하는 경우 해당 컨텍스트에 로드된 형식 개체만 사용합니다. MetadataLoadContext 형식을 런타임 형식과 혼합하는 것은 지원되지 않습니다. 예를 들어 MetadataLoadContexttestedType 형식을 고려합니다. 다른 형식을 할당할 수 있는지 테스트해야 하는 경우 typeof(MyType).IsAssignableFrom(testedType)과 같은 코드를 사용하지 마세요. 대신 이와 같은 코드를 사용합니다.

Assembly matchAssembly = mlc.LoadFromAssemblyPath(typeof(MyType).Assembly.Location);
Type matchType = assembly.GetType(typeof(MyType).FullName!)!;

if (matchType.IsAssignableFrom(testedType))
{
    Console.WriteLine($"{nameof(matchType)} is assignable from {nameof(testedType)}");
}

예시

전체 코드 예제를 보려면 MetadataLoadContext 샘플을 사용하여 어셈블리 콘텐츠 검사를 참조하세요.

참고 항목