2012. 2. 17. 06:39

How to load an assembly at runtime that is located in a folder that is not the bin folder of the application

A.dll
B.dll
Common.dll 

이 있습니다. Common.dll 은 A, B 모두에게 사용되기 때문에 같이 개발되고 빌드됩니다. 하지만 A.dll 과 B.dll 은 각기 다른 목적을 가지고 있기 때문에 다른 위치에 배포됩니다. 예를 들어

Test1/
A.dll
Common.dll
Test2/
B.dll
Common.dll

이렇게 배포를 했는데 문제가 생겼습니다. Test1, Test2 는 각기 다르게 배포되고 Common.dll 은 여러버전이 존재할 수 있습니다. A 가 처음 로딩될 때는 Test1 의 Common.dll 이 정상적으로 로딩되었으나, 그 다음에 B가 로디오될 때는 Test2 에 있는 Common.dll 이 아니라 이미 로딩되어 있는 Test1/Common.dll 을 그대로 사용하는 문제였습니다. (A.dll 과 B.dll 은 모두 COM 이기 때문에 배포시 'regasm.exe /codebase a.dll" 과 같이 codebase 로 글로벌하게 등록되어 있습니다.) 

이 문제를 수정하기 위해 자료를 찾다가 MS 에서 제공하는 아래 링크 정보를 찾았습니다.

http://support.microsoft.com/kb/837908 

3가지 방법을 소개 하고 있는데 그중에 3번째인 AssemblyResolve 이벤트라는 재밌는 녀석이 나옵니다.

핸들러 등록 방법

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += 
    new ResolveEventHandler(MyResolveEventHandler);

핸들러 코드 예제

private Assembly MyResolveEventHandler(object sender,ResolveEventArgs args)
{
	//This handler is called only when the common language runtime tries to bind to the assembly and fails.

	//Retrieve the list of referenced assemblies in an array of AssemblyName.
	Assembly MyAssembly,objExecutingAssemblies;
	string strTempAssmbPath="";

	objExecutingAssemblies=Assembly.GetExecutingAssembly();
	AssemblyName [] arrReferencedAssmbNames=objExecutingAssemblies.GetReferencedAssemblies();
			
	//Loop through the array of referenced assembly names.
	foreach(AssemblyName strAssmbName in arrReferencedAssmbNames)
	{
		//Check for the assembly names that have raised the "AssemblyResolve" event.
		if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(","))==args.Name.Substring(0, args.Name.IndexOf(",")))
		{
			//Build the path of the assembly from where it has to be loaded.				
			strTempAssmbPath="C:\\Myassemblies\\"+args.Name.Substring(0,args.Name.IndexOf(","))+".dll";
			break;
		}

	}
	//Load the assembly from the specified path. 					
	MyAssembly = Assembly.LoadFrom(strTempAssmbPath);					

	//Return the loaded assembly.
	return MyAssembly;			
}

주의: 위 코드가 제기된 문제를 해결했다는 건 아닙니다. 아직 적용을 해보지 못했습니다.