몇 가지 메서드를 정의하는 인터페이스를 사용하는 여러 끝점 (C# 클래스)이있는 예제 응용 프로그램이 있습니다. 이 엔드 포인트는 자체 클래스 라이브러리에 있습니다. "EndPoints.EndPoint1"라는 어셈블리에AppDomain 만들기 및 하위 폴더에있는 어셈블리에서 메서드 호출
라는 어셈블리에서에게 "엔드 포인트"
namespace EndPoints
{
public interface IEndPoint
{
void Initialize(XmlDocument message);
bool Validate();
void Execute();
}
}
namespace EndPoints
{
public class EndPoint1 : IEndPoint
{
private XmlDocument _message;
public void Initialize(XmlDocument message)
{
_message = message;
Console.WriteLine("Initialize EndPoint1");
}
public bool Validate()
{
Console.WriteLine("Validate EndPoint1");
return true;
}
public void Execute()
{
Console.WriteLine("Execute EndPoint1");
}
}
}
사용하고 해당 클래스를 찾을 엔드 포인트를 "선택"할 응용 프로그램 , 그것의 인스턴스를 생성 한 다음 차례대로 메소드를 호출하십시오.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// Generate "random" endpoint name
string endPointName = GetEndPointName();
// Get the class name from the namespaced class
string className = GetClassName(endPointName);
// Dummy xmldocument that used to pass into the end point
XmlDocument dummyXmlDocument = new XmlDocument();
// Load appropriate endpoint assembly because the application has no reference to it so the assembly would not have been loaded yet
LoadEndPointAssembly(endPointName);
// search currently loaded assemblies for that class
var classTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => p.FullName == endPointName)
.ToList();
// cycle through any found types (should be 1 only)
for (int i = 0; i < classTypes.Count; i++)
{
var classType = classTypes[i];
IEndPoint classInstance = Activator.CreateInstance(classType) as IEndPoint;
classInstance.Initialize(dummyXmlDocument);
if (classInstance.Validate())
{
classInstance.Execute();
}
}
}
private static void LoadEndPointAssembly(string endPointName)
{
using (StreamReader reader = new StreamReader(endPointName + ".dll", System.Text.Encoding.GetEncoding(1252), false))
{
byte[] b = new byte[reader.BaseStream.Length];
reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));
reader.Close();
AppDomain.CurrentDomain.Load(b);
}
}
private static string GetEndPointName()
{
// Code to create "random" endpoint class name
Random rand = new Random();
int randomEndPoint = rand.Next(1, 4);
return string.Format("EndPoints.EndPoint{0}", randomEndPoint);
}
private static string GetClassName(string namespacedClassName)
{
string className = null;
string[] components = namespacedClassName.Split('.');
if (components.Length > 0)
{
className = components[components.Length - 1];
}
return className;
}
}
}
다음을 달성하기 위해 응용 프로그램을 변경하고 싶습니다.
- 각 끝점 어셈블리 (및 사용되는 모든 구성 파일 및/또는 다른 어셈블리)는 응용 프로그램 폴더 아래의 하위 폴더에 들어 있습니다. 하위 폴더 이름은 끝점 클래스의 이름이됩니다. "EndPoint1" - 각 엔드 포인트는 자체 appdomain에서 실행됩니다.
그러나 지금까지이 문제를 해결할 수 없었습니다. appdomain을 만들 때 AppDomainSetup의 ApplicationBase 및 PrivateBinPath 속성을 설정하여 사용할 하위 폴더를 지정하더라도 적절한 어셈블리를로드하지 못했다는 예외가 계속 발생합니다. 예 :
AppDomain appDomain = null;
AppDomain root = AppDomain.CurrentDomain;
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = root.SetupInformation.ApplicationBase + className + @"\";
setup.PrivateBinPath = root.SetupInformation.ApplicationBase + className + @"\";
appDomain = AppDomain.CreateDomain(className, null, setup);
그런 다음 새로 생성 된 appDomain에서 Load 메서드를 사용하여 어셈블리를로드하려고했습니다. 그 때 오류가 발생합니다.
해당 어셈블리를로드하고 인터페이스에 정의 된 메서드를 호출하는 방법에 대한 의견이 있으십니까? 많은 감사합니다.
AppDomain.Load 메서드는 찾고있는 것과 다른 현재 AppDomain에서 어셈블리를로드하고 있습니다. 미샬의 대답과 같은 MarshalByRefDerived 로더가 필요합니다. –