다음을 통해 공유


System.Runtime.Loader.AssemblyLoadContext 정보

클래스는 AssemblyLoadContext .NET Core에서 도입되었으며 .NET Framework에서 사용할 수 없습니다. 이 문서에서는 개념 정보를 사용하여 AssemblyLoadContext API 설명서를 보완합니다.

이 문서는 동적 로드를 구현하는 개발자, 특히 동적 로드 프레임워크 개발자와 관련이 있습니다.

AssemblyLoadContext란?

모든 .NET 5+ 및 .NET Core 애플리케이션은 암시적으로 사용합니다 AssemblyLoadContext. 종속성을 찾고 로드하기 위한 런타임의 공급자입니다. 종속성이 로드될 때마다 인스턴스를 AssemblyLoadContext 호출하여 찾습니다.

  • AssemblyLoadContext는 관리되는 어셈블리 및 기타 종속성을 찾고, 로드하고, 캐싱하는 서비스를 제공합니다.
  • 동적 코드 로드 및 언로드를 지원하기 위해 자체 인스턴스에서 코드 및 해당 종속성을 로드하기 위한 격리된 컨텍스트를 AssemblyLoadContext 만듭니다.

버전 관리 규칙

단일 AssemblyLoadContext 인스턴스는 Assembly당 정확히 하나의 버전을 로드하는 것으로 제한됩니다. 해당 이름의 어셈블리가 이미 로드된 인스턴스에 대해 AssemblyLoadContext 어셈블리 참조가 확인되면 요청된 버전이 로드된 버전과 비교됩니다. 로드된 버전이 요청된 버전과 같거나 높은 경우에만 해결이 성공합니다.

여러 AssemblyLoadContext 인스턴스가 필요한 경우는 언제인가요?

단일 AssemblyLoadContext 인스턴스가 한 버전의 어셈블리만 로드할 수 있다는 제한은 코드 모듈을 동적으로 로드할 때 문제가 될 수 있습니다. 각 모듈은 독립적으로 컴파일되며 모듈은 서로 다른 버전의 Assembly에 따라 달라질 수 있습니다. 일반적으로 사용되는 라이브러리의 다른 버전에 대해 서로 다른 모듈이 의존할 때 문제가 자주 발생합니다.

동적으로 코드 AssemblyLoadContext 로드를 지원하기 위해 API는 동일한 애플리케이션에서 충돌하는 버전의 Assembly 로드를 제공합니다. 각 AssemblyLoadContext 인스턴스는 각각 AssemblyName.Name 을 특정 Assembly 인스턴스에 매핑하는 고유한 사전을 제공합니다.

또한 나중에 언로드할 수 있도록 코드 모듈과 관련된 종속성을 그룹화하기 위한 편리한 메커니즘을 제공합니다.

AssemblyLoadContext.Default 인스턴스

인스턴스는 AssemblyLoadContext.Default 시작 시 런타임에 의해 자동으로 채워집니다. 기본 검색을 사용하여 모든 정적 종속성을 찾아 찾습니다.

가장 일반적인 종속성 로드 시나리오를 해결합니다.

동적 종속성

AssemblyLoadContext 에는 재정의할 수 있는 다양한 이벤트 및 가상 함수가 있습니다.

인스턴스는 AssemblyLoadContext.Default 이벤트 재정의만 지원합니다.

관리되는 어셈블리 로드 알고리즘, 위성 어셈블리 로드 알고리즘관리되지 않는(네이티브) 라이브러리 로드 알고리즘 문서는 사용 가능한 모든 이벤트 및 가상 함수를 참조합니다. 이 문서에서는 로드 알고리즘에서 각 이벤트 및 함수의 상대 위치를 보여 줍니다. 이 문서에서는 해당 정보를 재현하지 않습니다.

이 섹션에서는 관련 이벤트 및 함수에 대한 일반적인 원칙을 설명합니다.

  • 반복 가능해야 합니다. 특정 종속성에 대한 쿼리는 항상 동일한 응답을 생성해야 합니다. 동일한 로드된 종속성 인스턴스를 반환해야 합니다. 이 요구 사항은 캐시 일관성을 위한 기본 사항입니다. 특히 관리되는 어셈블리의 경우, Assembly 캐시를 만듭니다. 캐시 키는 간단한 어셈블리 이름 AssemblyName.Name입니다.
  • 일반적으로 던지지 않습니다. 이러한 함수는 요청된 종속성을 찾을 수 없을 때 throw하지 않고 반환 null 될 것으로 예상됩니다. throw 연산은 검색을 조기에 종료시키고 호출자에게 예외를 전달합니다. 예외 던지기는 손상된 어셈블리 또는 메모리 부족 상태와 같은 예기치 않은 오류로 제한되어야 합니다.
  • 재귀를 피하십시오. 이러한 함수 및 처리기는 종속성을 찾기 위한 로드 규칙을 구현합니다. 구현은 재귀를 트리거하는 API를 호출해서는 안 됩니다. 코드는 일반적으로 특정 경로 또는 메모리 참조 인수가 필요한 AssemblyLoadContext 로드 함수를 호출해야 합니다.
  • 올바른 AssemblyLoadContext에 로드합니다. 종속성을 로드할 위치를 선택하는 것은 애플리케이션별로 다릅니다. 선택은 이러한 이벤트 및 함수에 의해 구현됩니다. 코드가 AssemblyLoadContext load-by-path 함수를 호출할 때 코드를 로드하려는 인스턴스에서 호출합니다. 때때로 null을 반환하고 AssemblyLoadContext.Default이 로드를 처리하도록 하는 것이 가장 간단한 옵션일 수 있습니다.
  • 스레드 경합에 유의하세요. 로드는 여러 스레드에 의해 트리거될 수 있습니다. AssemblyLoadContext는 스레드 경합을 방지하기 위해 어셈블리를 원자적으로 캐시에 추가하여 처리합니다. 경주 패자의 인스턴스는 삭제됩니다. 구현 논리에서 여러 스레드를 제대로 처리하지 않는 추가 논리를 추가하지 마세요.

동적 종속성은 어떻게 격리되는가?

AssemblyLoadContext 인스턴스는 Assembly 인스턴스와 Type 정의에 대한 고유한 범위를 나타냅니다.

이러한 종속성 간에는 이진 격리가 없습니다. 이름으로 서로를 찾지 못하여 격리됩니다.

AssemblyLoadContext:

  • AssemblyName.Name 는 다른 Assembly 인스턴스를 참조할 수 있습니다.
  • Type.GetType 는 동일한 형식에 대해 다른 형식 인스턴스를 반환할 수 있습니다 name.

공유 종속성

인스턴스 간에 AssemblyLoadContext 종속성을 쉽게 공유할 수 있습니다. 일반 모델은 AssemblyLoadContext 종속성을 로드하는 모델입니다. 다른 하나는 로드된 어셈블리에 대한 참조를 사용하여 종속성을 공유합니다.

이 공유는 런타임 어셈블리에 필요합니다. 이러한 어셈블리는 AssemblyLoadContext.Default에만 로드할 수 있습니다. 프레임워크(예ASP.NET: 또는 WPFWinForms.)에도 동일한 것이 필요합니다.

공유 종속성을 AssemblyLoadContext.Default에 로드하는 것이 좋습니다. 이 공유는 일반적인 디자인 패턴입니다.

공유는 사용자 지정 AssemblyLoadContext 인스턴스의 코딩에서 구현됩니다. AssemblyLoadContext 에는 재정의할 수 있는 다양한 이벤트 및 가상 함수가 있습니다. 이 함수들 중 어떤 것이 다른 Assembly 인스턴스에 로드된 AssemblyLoadContext 인스턴스에 대한 참조를 반환할 때, 그 Assembly 인스턴스는 공유됩니다. 표준 부하 알고리즘은 일반적인 공유 패턴을 간소화하기 위해 AssemblyLoadContext.Default에 로딩을 맡깁니다. 자세한 내용은 관리되는 어셈블리 로드 알고리즘을 참조하세요.

형식 변환 문제

AssemblyLoadContext 인스턴스에 동일한 형식 정의가 포함되어 있어도 name형식은 서로 다릅니다. 동일한 Assembly 인스턴스에서 오는 경우에 한해서 같은 유형입니다.

문제를 복잡하게 하기 위해 이러한 일치하지 않는 형식에 대한 예외 메시지는 혼동될 수 있습니다. 형식은 단순 형식 이름으로 예외 메시지에서 참조됩니다. 이 경우 일반적인 예외 메시지는 다음과 같은 형식입니다.

'IsolatedType' 형식의 개체를 'IsolatedType' 형식으로 변환할 수 없습니다.

형식 변환 문제 디버그

일치하지 않는 형식 쌍이 있는 경우 다음 사항도 알아야 합니다.

주어진 두 개체 ab를 평가하는 것이 디버거에서 도움이 됩니다.

// In debugger look at each assembly's instance, Location, and FullName
a.GetType().Assembly
b.GetType().Assembly
// In debugger look at each AssemblyLoadContext's instance and name
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(a.GetType().Assembly)
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(b.GetType().Assembly)

형식 변환 문제 해결

이러한 형식 변환 문제를 해결하기 위한 두 가지 디자인 패턴이 있습니다.

  1. 일반적인 공유 형식을 사용합니다. 이 공유 형식은 기본 런타임 형식이거나 공유 어셈블리에서 새 공유 형식을 만드는 작업을 포함할 수 있습니다. 공유 형식은 애플리케이션 어셈블리에 정의된 인터페이스 인 경우가 많습니다. 자세한 내용은 종속성을 공유하는 방법에 대해 읽어보세요.

  2. 마샬링 기술을 사용하여 한 형식에서 다른 형식으로 변환합니다.