ไม่สามารถรับชนิดจากแอสเซมบลีหลังจาก ReflectionOnlyLoadFrom
ฉันได้ปรึกษาโค้ดบนเว็บไซต์ http://codeproject.com ด้วยชื่อเรื่อง "Loading Assemblies from Anywhere into a New AppDomain" ของ Marius Bancila แต่ฉันได้ทดสอบข้อผิดพลาดดังภาพที่แนบมาตอนนี้ฉันไม่ทราบวิธีแก้ไขหวังว่าคุณจะช่วยได้ขอบคุณ
รหัสลิงก์ https://www.codeproject.com/Articles/453778/Loading-Assemblies-from-Anywhere-into-a-New-AppDom#_articleTop
ทดสอบ
public class Program
{
[STAThread]
public static void Main()
{
var project = @"D:\Github\BeyConsPlugin\BeyConsProject\bin\x64\Debug\BeyConsRevitProject.dll";//Path to assembly
var manager = new AssemblyReflectionManager();
var success = manager.LoadAssembly(project, Guid.NewGuid().ToString());
if (success)
{
var result = manager.Reflect(project, (a) =>
{
return a.GetTypes();
});
Console.WriteLine(string.Join("\n", result.Select(x => x.Name)));
}
Console.ReadKey();
manager.UnloadAssembly(project);
}
}
ข้อผิดพลาด
คำตอบ
ไม่ได้ตั้งค่าตัวแก้ไขการประกอบ
รหัสของ Marius มีข้อบกพร่องAssemblyReflectionProxyเกี่ยวกับการที่ Assembly Resolver ไม่ได้ตั้งค่าไว้หากคุณเรียกLoadAssemblyไม่เหมือนReflect<>ที่ทำ
ขึ้นอยู่กับวิธีสร้างโดเมนแอปลูกเมื่อโหลดแอสเซมบลีอาจเข้าถึงโฟลเดอร์ตามที่ระบุไว้ในระหว่างการสร้างเท่านั้น หากคุณต้องการประกอบโพรบที่อื่นสำหรับแอสเซมบลีหรือการอ้างอิงคุณต้องมี Assembly Resolver เมื่อ. NET กำลังมองหาแอสเซมบลีสำหรับโดเมนจะเรียกตัวจัดการของคุณตามที่ระบุไว้ในReflectionOnlyAssemblyResolveเหตุการณ์ของแอสเซมบลี หากไม่ได้ระบุไว้หรือหากตัวแก้ไขล้มเหลวในการค้นหาชุดประกอบจะทำให้เกิดฟองขึ้นและทำให้เกิดข้อยกเว้นการโหลดล้มเหลว
ฉันขอแนะนำให้คุณเปลี่ยนรหัสจาก:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
...ถึง:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve // <---- add me
+= OnReflectionOnlyResolve;
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
คุณสามารถดูสิ่งนี้ได้ในรหัสดั้งเดิมของ Sacha ซึ่ง Marius ใช้ของเขา
เพิ่มข้อกำหนดสำหรับการแก้ไขเส้นทาง
ปัญหาอื่น ๆ ของรหัสคือทั้งสองสมมติว่าเมื่อโหลดแอสเซมบลีหนึ่งชุดแอสเซมบลีที่อ้างอิงใด ๆ อยู่ในโฟลเดอร์เดียวกันซึ่งอาจไม่เป็นเช่นนั้นเสมอไป
แก้ไขAssemblyReflectionProxyเพื่อรวมรายการเส้นทางที่จะตรวจสอบ:
public List<string> ResolvePaths { get; set; }
จากนั้นแก้ไข OnReflectionOnlyResolve ให้มีลักษณะดังต่อไปนี้:
private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
{
Assembly loadedAssembly =
AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()
.FirstOrDefault(
asm => string.Equals(asm.FullName, args.Name,
StringComparison.OrdinalIgnoreCase));
if (loadedAssembly != null)
{
return loadedAssembly;
}
foreach (var tryFolder in ResolvePaths)
{
var asmName = args.Name.Split(',');
var assemblyPath = Path.Combine(tryFolder, asmName[0] + ".dll");
if (!File.Exists(assemblyPath))
return null;
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
}
ชื่ออะไร?
ReflectionOnlyLoadบทความทั้งสองละเลยที่จะชี้ให้เห็นพิมพ์ดีเมื่อใช้ แม้ว่าอย่างน้อย Sacha ก็พูดถึงรหัสของเขาว่าเป็น"ตัวสร้างโค้ด"แต่ฉันก็อดสงสัยไม่ได้ว่าบทความทั้งสองบทความที่มี" Loading Assemblies.... into a New AppDomain"อาจมีการตีความบ้าง
จุดมุ่งหมายของการReflectionOnlyLoadเป็นเพียงที่ - สำหรับการสะท้อน หากคุณโหลดแอสเซมบลีด้วยวิธีนี้คุณจะไม่สามารถรันโค้ดใด ๆ ในนั้นได้ นอกจากนี้และค่อนข้างน่าแปลกใจในตอนแรกสำหรับโปรแกรมเมอร์ตัวสะท้อนแอสเซมบลีส่วนใหญ่รวมถึงฉันก็คือการโทรGetCustomAttributesจะล้มเหลวด้วย (เพราะมันพยายามที่จะ"อินสแตนซ์"ประเภทในแอสเซมบลี)
หากคุณกำลังเขียนระบบปลั๊กอินของคุณเองซึ่งแต่ละปลั๊กอินมี App Domain ของตัวเองวิธีการAssemblyสะท้อนและโหลดจะมีประโยชน์สำหรับขั้นตอนต่างๆของไปป์ไลน์การโหลดระบบปลั๊กอิน:
- First pass - ใช้
ReflectionOnlyLoadเป็นวิธีตรวจสอบปลั๊กอินเพื่อดูว่าถูกต้องหรือไม่ บางทีคุณอาจต้องการเรียกใช้การตรวจสอบความปลอดภัยบางอย่างอย่างปลอดภัยเนื่องจากทราบว่าไม่มีรหัสปลั๊กอินใดที่สามารถทำงานได้ในช่วงนี้ - ครั้งที่สอง - หลังจากตรวจสอบปลั๊กอินแล้วคุณสามารถ
Load/LoadFromประกอบและรันโค้ดได้อย่างปลอดภัย