본문 바로가기

.NET/C#

참조된 어셈블리의 Reflection 트러블 슈팅

우리는 가끔씩 리플랙션을 사용한다.
사용하는 목적 또한 다양하고 리플랙션의 장점 또한 무궁무진 하다.
 
오늘 이야기할 내용은 어셈블리는 리플랙션을 하는데 있어 무척 도움이 될만한 내용을 살펴보겠다.
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
 
namespace ConsoleTest1
{
       class Program
       {
             static void Main(string[] args)
             {
                    try
                    {
                           BindingFlags flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
                           // 실행중인 응용프로그램의 경로를 표시한다.
                           Console.WriteLine(Environment.CurrentDirectory);
 
                           // 빌드된 웹페이지의 dll 을 로드한다.
                           Assembly asm = Assembly.LoadFrom(@"C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\UmcTest\ConsoleTest1\bin\Debug\App_Web_articlecontrol.ascx.51af1afc.dll");
 
                           // 모듈을 로드한다.
                           foreach (Module module in asm.GetModules())
                           {
                                 // 모듈 이름 출력
                                 Console.WriteLine(module.Name);
 
                                 // 클래스의 Type 을 가져온다.
                                 Type type = asm.GetType("WebAdmin_05Article_Controls_ArticleControl");
                           }       
                    }
                    catch (Exception ex)
                    {
                           Console.WriteLine( ex.Message );
                    }
             }
       }
}
 
 
우선 위와 같은 간단한 리플랙션 소스를 놓고 차근차근 살펴보겠다.
 
위 소스는 실행결과 아무런 예외도 내뱉지 않는다.
 
 
어셈블리에 위와 같은 WebAdmin_05Article_Controls_ArticleControl 타입은 분명 존재한다. 그래서 에러가 나지 않는 것일까?
 
결론부터 말하면 절대 아니다.
참고로 위 App_Web_articlecontrol.ascx.51af1afc.dll 어셈블리는 Umc.Core.Dll 을 참조하고 있으며, Umc.Core.Dll 이 있어야 정상적으로 작동할 수 있다.
 
App_Web_articlecontrol.ascx.51af1afc.dll 어셈블리와 Umc.Core.Dll 은 같은 폴더에 놓이게 되면 닷넷 어셈블리는 자동으로 App_Web_articlecontrol.ascx.51af1afc.dll이 로드될 때 Umc.Core.Dll 어셈블리를 참조하게 된다.
 
그럼 좀더 예외상황을 자세히 보도록 하기 위해 다음의 구문에 인자값을 추가해 주자.
 
// 클래스의 Type 을 가져온다.
Type type = asm.GetType("WebAdmin_05Article_Controls_ArticleControl", true, false);
 
위와같이 수정되었으니 다시 한번 실행해 보겠다.
 
 
보시다시피 뭐라뭐라 Exception 메시지가 떠 버렸다.
 
위에서 설명한대로 참조한 어셈블리(Umc.Core.Dll) 이 존재하지 않기에 어셈블리를 정상적으로 로드하지 못한 결과다.
 
만약, 하나의 응용프로그램에 참조된 어셈블리는 한 두개가 아닌, 수개 내지 수십개라고 가정해 볼 때 리플랙션을 수행하는 개발자 입장에선 곤욕이 따로 없을 것이다.
 
그럼 이와 같은 예외가 발생할 때 어떻게 참조된 어셈블리는 알아낼 수 있는지 알아보자.
 
그러기 위해 약간의 소스를 변경해 보겠다.
                                    …
                                    …
                                    …
                           // 모듈을 로드한다.
                           foreach (Module module in asm.GetModules())
                           {
                                 // 모듈 이름 출력
                                 Console.WriteLine("Module Name : " + module.Name);
 
                                 // 클래스의 Type 을 가져온다.
                                 Type[] type = asm.GetTypes();
                           }
                    }
                    catch (ReflectionTypeLoadException ex)
                    {
                           Console.WriteLine( ex.Message );
                    }
 
단순히 어셈블리의 모듈별로 Types 를 가져오도록 했다.
 
 
위에서 말한대로 참조된 어셈블리를 로드할 수 없어 ReflectionTypeLoadException이 떠버렸다.
 
그럼 참조하지 못한 수개 또는 수십개의 어셈블리를 나열해 보자.
 
다음과 같이 소스를 수정해 보기 바란다.
 
catch (ReflectionTypeLoadException ex)
{
       Console.WriteLine("-----------------------------------------------------------");
       foreach (Exception ex1 in ex.LoaderExceptions)
       {
             FileNotFoundException fex = ex1 as FileNotFoundException;
             if (fex != null)
             {
                    Console.WriteLine(fex.FileName);
             }
       }
}
 
 
하하하.. 결과는 대만족이다.
만약 여러 서드파티 제품 등의 어셈블리, 또는 기타 어셈블를 참조할 경우 참조하지 못한 어셈블리들의 리스트가 쭈욱 뜬다.
 
위와같이 참조하지 못한 어셈블리에 대해 재귀호출을 통하여Environment.CurrentDirectory 로 어셈블리를 복사하면서 수행하게 되면 리플랙션을 잘 작동 될 것이다.
 
그럼 이만 ^^;

태그