외부 Assembly를 찾는 방법은?

안녕하세요. :smile:

C# (4.6.1) Assembly에 관한 질문입니다.

저는 외부에 있는(상속받은) 어셈블리가 필요합니다.

Assembly.LoadFile(".dll") 방식으로 어셈블리를 찾을 수도 있지만

외부 시점에서 Assembly를 생성하고 있습니다.

// Service.dll
public Service : Base
{
    // Base에서 사용할 수 있도록 생성.
    public override Assembly Assem => Assembly.GetExecutingAssembly();
}

그래서,
외부에서 생성한 assembly에 접근하여 사용하고 있습니다.

// Base.dll
public class Base
{
    public virtual Assembly Assem => null;
    public Base()
    {
        // 외부 dll에서 생성된 assembly 사용.
        Stream stream = Assem.GetManifestResourceStream("<queryfile.yaml>");
    }
}

<요약>

  • 상속 관계를 통해 외부 Assembly를 찾을 수도 있을까요?

읽어주셔서 감사합니다. :sweat_smile:



처음 작성한 질문 (누르면 펼쳐짐)

제가 외부 Assembly 객체 정보를 받기 위한 로직을 구현하고 있는데요.
최소한으로 필요한 부분만 샘플로 작성했습니다.

내용은 하단 DataSerialize.dll 부분에서 Proxy.dll의 Assembly를 가져오고 싶은데요.
이유는 Proxy.dll 안에 포함 리소스로 포함된 .yaml 파일을 읽어들이기 위함입니다.

일단 정상 동작하는 것을 빨리 보고 싶어서
아래와 같이 override를 통해 Assembly에 접근할 수 있도록 구현은 했는데요.

이런 비슷한 상황에서 어떻게 하는 것이 좋은지 알고 싶습니다.
그리고 SelectProxy 같은 클래스가 수십 수백개일 때에는 또 불편할 것 같은데요.
(어셈블리를 위한 클래스를 또 만들어보기도 하고…)

암튼 저는 이런 상황이 자주 생겨서 지금까지는 크게 중요하지 않다 생각하고,
아래처럼 대충 넘어갔는데요.

이런 상황에서는 어떻게 하면 좋을지 소중한 조언 부탁드립니다!!

<내용 요약>

  • 아래는 정상 동작하는 샘플 소스코드 입니다.
  • Assembly를 Override를 통해 재정의 해서 접근하는 것이 올바른지?
  • Assembly를 가져오는 다른 방법?
  • 구조 문제?
  • Assembly 이해, 사용에 대해 잘못 생각하고 있는지?
  • 애초에 잘못된 질문인지…

Proxy.dll

// Assembly Proxy.dll
public class SelectProxy : ProxyBase
{
    protected override string QueryName => "namespace.folder.filename.yaml";
    protected override Assembly OnLoadAssembly() => 
        Assembly.GetExecutingAssembly();
}

ProxyBase.dll

// Assembly ProxyBase.dll
public class ProxyBase
{
    public abstract string QueryName { get }; 
    public override Assembly OnLoadAssembly()
    {
        return Assembly.GetExecutingAssembly();
    }
  
    public void Read(Assembly assembly)
    {
        var source = Read<DataModel>(QueryName, OnLoadAssembly());

        this.Execute(source);
    }
}

DataSerialize.dll

// Assembly DataSerialize.dll
public class YamlProvider
{
    publicoverride Read<T>(string resName, Assembly assem)
    {
        using (Stream stream = assem.GetManifestResourceStream(resName))
        using (StreamReader reader = new StreamReader(stream))
        {
    	    var deserializer = new DeserializerBuilder()
	        .WithNamingConvention(CamelCaseNamingConvention.Instance)
		    .Build();

            return deserializer.Deserialize<T>(reader.ReadToEnd());
        }
    }
}
좋아요 1

코드만으로는 정확히 어떤걸 구현하고자 하신 것인지 잘 전달이 안되는 것 같아, 답변이 좀 엉뚱하게 들어갈 수도 있을 것 같습니다.

지금 생각하시는 것이 동적 모듈 로딩에 관한 것이라면, 어셈블리의 경우 한 가지 결정적인 문제가 있습니다. 닷넷 프레임워크 때에는 앱 도메인을 따로 만들어 앱 도메인 단위로 만들고 부수는 방식으로 어셈블리 동적 로딩을 처리했지만 (이것도 효율적인 형태는 아닙니다.), 닷넷 코어에 와서는 이 방법도 사용하는데 제약이 있습니다.

이 제약으로 인해서 발생하는 현상은, 어셈블리를 한 번 로딩하고 필요 없을 때 "로딩 해제"를 할 수 없어 어셈블리 DLL 파일이 계속 잠김 상태로 남는 것입니다.

그래서 말입니다만, 아래 글의 내용이 구현하고자 하는 내용에 가까운 것인지 혹시 알려주실 수 있을까요?

.NET Core에서 어셈블리 언로드 기능을 사용하고 디버그하는 방법 | Microsoft Docs

좋아요 2

@rkttu 질문을 명확하게 수정하겠습니다.

외부에 있는 어셈블리 안에 포함된리소스 파일을 읽는 질문인데
설명주신 부분이 큰 도움이 되었어요!!

감사합니다. :smile:

좋아요 2

원래 질문은 답변자의 답변이 없었다면 지우는건 상관이 없겠지만 답변이 있으면 삭제하지 않고 다른분들이 추척할 수 있도록 두는게 본 게시물을 이해하는데 도움이 될것 같아 삭제 안하시는게 어떠할까요?

좋아요 3
  1. 특정 경로의 DLL 목록을 가져옵니다.
  2. DLL에서 Assembly.FromFile()등으로 Assembly를 로딩합니다.
  3. 로딩된 assembly.GetTypes()의 목록을 이용해, 해당 타입이 클래스이고, Base 클래스에서 상속 되었는지를 찾습니다.

이 내용이 맞을까요?

좋아요 3

@dimohy 앗 저거 누르면 펼쳐집니다!!
저도 그렇게 생각해서 숨겨뒀어요. :smile:

(튜토리얼에서 배운기능)

좋아요 1

@dimohy @rkttu 감사합니다. :smile:
말씀해주신 방법으로 작업 해보고 후기 남겨볼께요!!

좀 더 해 보고 나중에 .dll해제애 대한 질문도 드려야할 것 같습니다. :sweat_smile:

좋아요 1