2010-04-17 27 views
12

Chúng tôi triển khai một khung plugin cho ứng dụng của chúng tôi và lắp ráp các plugin bằng cách sử dụng Assembly.Loadfrom. Sau đó, chúng tôi sử dụng GetTypes() và kiểm tra thêm các loại với từng tệp plugin cho Giao diện được hỗ trợ.Assembly.GetTypes() - ReflectionTypeLoadException

Đường dẫn cho plugin được cung cấp bởi người dùng và chúng tôi xoay vòng qua từng tệp trong thư mục để xem liệu plugin (plugin) có hỗ trợ giao diện plugin của chúng tôi hay không. Nếu có, chúng ta tạo một thể hiện, nếu không chúng ta chuyển sang tập tin tiếp theo.

Chúng tôi xây dựng hai phiên bản phần mềm từ một cơ sở mã (appA_1 và appA_2).

Tải plugin hoạt động tốt khi các plugin được tải bởi ứng dụng được xây dựng cùng lúc với tệp plugin. Tuy nhiên, nếu chúng ta xây dựng appA_2 và trỏ đến thư mục plugin của appA_1, chúng ta sẽ có ngoại lệ khi GetTypes() được gọi.

Phiên bản cơ bản của mã của chúng tôi là;

var pluginAssembly = Assembly.LoadFrom(FileName);  
foreach (var pluginType in pluginAssembly.GetTypes()) 
{ 

Chúng tôi nhận được ngoại lệ "ReflectionTypeLoadException".

Điều này có liên quan bởi vì chúng tôi muốn ứng dụng của chúng tôi có thể tải các loại plugin bất kỳ, được xây dựng bởi bất kỳ ai. Có cái gì chúng ta đang thiếu?

EDIT: Sau khi lặp qua LoaderExceptions, chúng tôi đã phát hiện ra rằng có một tệp libPublic.dll duy nhất tạo ra ngoại lệ System.IO.FileNotFoundException. Điều kỳ lạ là tệp này nằm trong thư mục ứng dụng và plugin được tham chiếu đến tệp dự án.

EDIT 2: Trong nhật ký ngoại lệ, chúng tôi tìm thấy những điều sau "So sánh tên lắp ráp dẫn đến việc không phù hợp: Revision Number"

+0

Thông báo ngoại lệ là gì? Ngoại lệ có ngoại lệ bên trong không? Thông điệp đó là gì? – dtb

+0

Bất kỳ lý do nào bạn không sử dụng một khung công tác hiện có như MEF? – dtb

+0

Bạn vẫn có thể tạo ra các vấn đề như thế này khi sử dụng MEF, mặc dù MEF chắc chắn là tiện dụng cho việc chăm sóc công việc grunt. –

Trả lời

14

Một vài điều:

  • Hãy chắc chắn rằng bạn không' t có hội đồng trùng lặp trong thư mục plugin (tức là hội đồng mà bạn đã tải trong ứng dụng chính của bạn từ thư mục ứng dụng của bạn.) Nếu không, khi bạn tải plugin của bạn, nó có thể tải một bản sao bổ sung của cùng một hội đồng. Điều này có thể dẫn đến các ngoại lệ thú vị như:

    Đối tượng (thuộc loại 'MyObject') không thuộc loại 'MyObject'.

  • Nếu bạn đang nhận được ngoại lệ khi instantiating một kiểu, bạn có thể cần phải xử lý AppDomain.AssemblyResolve:

    private void App_Startup(object sender, StartupEventArgs e) 
    { 
        // Since we'll be dynamically loading assemblies at runtime, 
        // we need to add an appropriate resolution path 
        // Otherwise weird things like failing to instantiate TypeConverters will happen 
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 
    } 
    
    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
        var domain = (AppDomain) sender; 
    
        foreach (var assembly in domain.GetAssemblies()) 
        { 
         if (assembly.FullName == args.Name) 
         { 
          return assembly; 
         } 
        } 
    
        return null; 
    } 
    

Tôi nhận ra đó là một chút lạ để phải nói với CLR đó, để giải quyết một hội đồng, tìm lắp ráp với tên chúng tôi đang sử dụng để giải quyết, nhưng tôi đã nhìn thấy những điều kỳ lạ xảy ra mà không có nó. Ví dụ, tôi có thể khởi tạo các loại từ một hội đồng plugin, nhưng nếu tôi cố gắng sử dụng TypeDescriptor.GetConverter, nó sẽ không tìm thấy TypeConverter cho lớp, mặc dù nó có thể thấy thuộc tính Converter trên lớp.


Nhìn vào chỉnh sửa của bạn, điều này có lẽ không gì gây ra ngoại lệ hiện tại của bạn, mặc dù bạn có thể gặp những vấn đề sau khi bạn làm việc với các plugin của bạn.

+1

Bạn thật tuyệt vời! Tôi đã có vấn đề lắp ráp trùng lặp, vì vậy câu trả lời này đã cứu tôi! – JoeCool

+0

Điều này cũng giải quyết được vấn đề của tôi. Tôi đang tải plug-in của mình, hiển thị UITypeEditor và TypeConverters tùy chỉnh và trong khi các loại của tôi sẽ tải, trình chỉnh sửa/trình chuyển đổi sẽ không khởi tạo. Ngoài ra, các trình cắm thêm của tôi được đặt trong thư mục con tương ứng với ứng dụng và đủ kỳ quặc, nếu tôi đặt trình cắm trong cùng thư mục với ứng dụng máy chủ, nó hoạt động tốt. Giải pháp này đã giúp các plugin hoạt động bất kể vị trí của chúng. – Mike

+0

Bạn hoàn toàn chính xác. Tôi cũng đang tải một hội đồng trong ứng dụng con đã tồn tại trong ứng dụng cha mẹ. Khi tôi nạp với AppDomain.CurrentDomain.GetAssemblies() tôi đã nhận được assembly và giải quyết vấn đề Loader trong GetTypes(). Cảm ơn rất nhiều :) @Dan Dryant –

0

Bạn đang nhận được phiên bản lắp ráp không khớp. Vì plugin của bạn đề cập đến điều này libPublic.dll, bạn phải phiên bản nó một cách cẩn thận và đặc biệt không bump sửa đổi/xây dựng/etc của nó. số ở mọi biên dịch.

2

Nhờ bài đăng này tôi có thể giải quyết ReflectionTypeLoadException mà tôi đã nhận được trong một UITypeEditor. Đó là một hội đồng thiết kế (một thẻ thông minh winforms được sử dụng tại thời điểm thiết kế) của một thư viện lớp tùy chỉnh, quét một số loại.

/// <summary> 
/// Get the types defined in the RootComponent. 
/// </summary> 
private List<Type> getAssemblyTypes(IServiceProvider provider) 
{ 
    var types = new List<Type>(); 
    try 
    { 
     IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost)); 
     ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService)); 
     AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
     { 
      foreach (var assembly in ((AppDomain)sender).GetAssemblies()) 
      { 
       if (assembly.FullName == args.Name) 
       { 
        return assembly; 
       } 
      } 

      return null; 
     }; 

     Type rootComponentType = resolution.GetType(host.RootComponentClassName, false); 
     types = rootComponentType.Assembly.GetTypes().ToList(); 
    } 
    catch 
    { 
    } 

    return types; 
} 
+0

IServiceProvider đến từ đâu? Làm thế nào nó có thể thu được? – Pangamma

Các vấn đề liên quan