2010-10-26 23 views
19

Kịch bản: Tôi đang sử dụng Khung mở rộng được quản lý để tải plugin (xuất) tại thời điểm chạy dựa trên một giao diện được xác định trong một dll riêng biệt . Trong giải pháp Visual Studio của tôi, tôi có 3 dự án khác nhau: Ứng dụng máy chủ, thư viện lớp (định nghĩa giao diện - "IPlugin") và một thư viện lớp khác thực hiện giao diện (xuất - MyPlugin.dll "). Máy chủ tìm kiếm xuất trong thư mục gốc của nó, vì vậy trong quá trình thử nghiệm, tôi xây dựng toàn bộ giải pháp và sao chép Plugin.dll từ thư mục bin/release thư viện lớp Plugin vào thư mục gỡ lỗi của máy chủ để DirectoryCatalog của máy chủ sẽ tìm thấy và có thể thêm nó vào tệp CompositionContainer. Plugin.dll không được tự động sao chép sau mỗi lần xây dựng lại, vì vậy tôi làm điều đó theo cách thủ công mỗi lần tôi thực hiện các thay đổi đối với hợp đồng/triển khai.MEF: "Không thể tải một hoặc nhiều loại được yêu cầu. Lấy các ngoại lệ tải để biết thêm thông tin"

Tuy nhiên, một vài lần tôi đã chạy các ứng dụng máy chủ mà không cần phải sao chép (một cập nhật) Plugin.dll đầu tiên, và nó đã ném một ngoại lệ trong thành phần:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information

Đây là tất nhiên do thực tế là Plugin.dll đang cố gắng nhập từ thực hiện phiên bản khác nhau của IPlugin, nơi các chữ ký thuộc tính/phương thức không khớp. Mặc dù dễ dàng tránh điều này trong một môi trường được kiểm soát và giám sát, bằng cách đơn giản tránh (duh) lỗi thời triển khai IPlugin trong thư mục plugin, tôi không thể dựa vào các giả định như vậy trong môi trường sản xuất, nơi có thể gặp phải các plugin cũ.

Vấn đề là ngoại lệ này có hiệu quả botches toàn bộ hành động Soạn thư và xuất khẩu không. Tôi đã có thể ưa thích rằng việc triển khai IPlugin không phù hợp chỉ đơn giản là bị bỏ qua, do đó xuất khẩu khác trong (các) danh mục, triển khai phiên bản chính xác của IPlugin, vẫn được nhập.

Có cách nào để thực hiện việc này không? Tôi đang nghĩ đến một trong vài lựa chọn tiềm năng:

  • Có một lá cờ để đặt trên CompositionContainer ("bỏ qua nhập khẩu không") trước hoặc khi gọi Soạn
  • Có một lá cờ tương tự để xác định trên <ImportMany()> Thuộc tính
  • Có cách "móc" vào quy trình lặp lại cơ bản Compose() và có thể xử lý từng (không nhập) riêng lẻ
  • Sử dụng ký tên mạnh để bằng cách nào đó chỉ tìm nhập thực hiện hiện tại phiên bản của IPlugin

Ý tưởng?

Trả lời

15

Tôi cũng đã chạy vào a similar problem.

Nếu bạn chắc chắn rằng bạn muốn bỏ qua các hội đồng "xấu" như vậy, thì giải pháp là gọi AssemblyCatalog.Parts.ToArray() ngay sau khi tạo từng danh mục lắp ráp. Điều này sẽ kích hoạt các ReflectionTypeLoadException mà bạn đề cập đến. Sau đó bạn có một cơ hội để bắt ngoại lệ và bỏ qua hội đồng xấu.

Khi bạn đã tạo các đối tượng AssemblyCatalog cho tất cả các cụm "tốt", bạn có thể tổng hợp chúng trong một số AggregateCatalog và chuyển cho nhà xây dựng CompositionContainer.

+0

Tôi sẽ xem xét. Và có, tôi chắc chắn tôi muốn bỏ qua chúng - Tôi không thể sử dụng chúng anyway, và họ mess up cho tất cả những cái tôi muốn, vì vậy đó là một no-brainer, không? :) – d7samurai

+0

@ d7samurai: Một số người sẽ kết thúc ở đây bằng cách googling thông điệp ngoại lệ. Tôi chỉ muốn nhấn mạnh cho họ rằng điều này không khắc phục được nguyên nhân cơ bản của lỗi. Ngoài ra, việc giới thiệu lỗi im lặng (còn gọi là "về lỗi tiếp tục hành vi" tiếp theo) không chính xác là không có trí tuệ; nó có thể làm phức tạp hóa việc dò tìm và chẩn đoán lỗi. Tôi khuyên bạn nên ít nhất cung cấp cho một số dấu hiệu cho người dùng rằng một cái gì đó xấu đã xảy ra. –

+0

Tất nhiên. Bởi "bỏ qua" tôi có nghĩa là "di chuyển trên mà không cho phép nó dừng lại toàn bộ quá trình nhập khẩu". Không có người dùng, vì đây là một Dịch vụ Windows, nhưng mọi thứ (bootstrapper) này đều được ghi lại, cả hai hoạt động bình thường và ngoại lệ (bao gồm việc bán tất cả các ngoại lệ trong "LoaderExceptions" - khi có thể áp dụng). – d7samurai

7

Vấn đề này có thể được gây ra bởi một số yếu tố (bất kỳ trường hợp ngoại lệ trên assembly được nạp), giống như ngoại lệ nói, hãy nhìn vào ExceptionLoader để (hy vọng) nhận được một số ý tưởng

Một vấn đề/giải pháp mà tôi thấy, là khi sử dụng DirectoryCatalog, nếu bạn không chỉ định tham số thứ hai "searchPattern", MEF sẽ tải TẤT CẢ các dll trong thư mục đó (bao gồm bên thứ ba) và bắt đầu tìm kiếm các loại xuất, cũng có thể gây ra vấn đề này, một giải pháp là có một tên quy ước trên tất cả các assembly xuất ra các loại, và chỉ rõ rằng trong constructor DirectoryCatalog, tôi sử dụng * _Plugin.dll, theo cách đó MEF sẽ chỉ nạp các assembly mà chứa xuất khẩu các loại

Trong trường hợp của tôi MEF đã được tải một dll NHibernate và ném một số lỗi phiên bản lắp ráp trên LoaderException (lỗi này có thể xảy ra với bất kỳ dlls trong thư mục), phương pháp này giải quyết được vấn đề

7

đây là ví dụ về các phương pháp được đề cập ở trên:

var di = new DirectoryInfo(Server.MapPath("../../bin/")); 

     if (!di.Exists) throw new Exception("Folder not exists: " + di.FullName); 

     var dlls = di.GetFileSystemInfos("*.dll"); 
     AggregateCatalog agc = new AggregateCatalog(); 

     foreach (var fi in dlls) 
     { 
      try 
      { 
       var ac = new AssemblyCatalog(Assembly.LoadFile(fi.FullName)); 
       var parts = ac.Parts.ToArray(); // throws ReflectionTypeLoadException 
       agc.Catalogs.Add(ac); 
      } 
      catch (ReflectionTypeLoadException ex) 
      { 
       Elmah.ErrorSignal.FromCurrentContext().Raise(ex); 
      } 
     } 

     CompositionContainer cc = new CompositionContainer(agc); 

     _providers = cc.GetExports<IDataExchangeProvider>(); 
+0

Điều này không làm việc cho ASP.NET MVC nếu bạn không sử dụng một tên miền riêng biệt, bởi vì Assembly.LoadFile tải tệp vào một tên miền khác. Để giải quyết nó, bạn chỉ cần sử dụng Assembly.LoadFrom. – Eben

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