5

Tôi đang thiết kế một khung plugin đơn giản cho một ứng dụng .NET 3.5 (WinForms).Một container IoC đơn giản cho một hệ thống plugin nhỏ

Ứng dụng hiện tại của chúng tôi cần bắt đầu hỗ trợ tải động và "hooking" các "plugin"/"tiện ích mở rộng" khác nhau mà ứng dụng này không biết lúc biên dịch.

Các tiện ích này sẽ được "nối" vào các khu vực khác nhau của ứng dụng, chẳng hạn như được xử lý như bộ điều khiển sự kiện của một số lớp nhất định.

Ví dụ (giản thể):

public class SomeSystem 
{ 
    public event Action<string> Completed; 

    public event Action<string> Failed; 

    public event Action<string> Stopped; 
} 

Một sử dụng trường hợp tôi muốn có là dành cho các nhà phát triển để có thể xác định xử lý cho các sự kiện như vậy trong một hội đồng plugin, mà không cần phải ứng dụng biết về họ .

Từ kiến ​​thức của tôi, các thùng chứa IoC cho phép tự động phát hiện các đối tượng trong thời gian chạy và đăng ký chúng trong một thùng chứa.

Là một container IoC có thể cũng làm điều này hooking vào các sự kiện khác nhau cho tôi? Hoặc là nhiệm vụ này dễ dàng hơn để làm mà không có một khuôn khổ như vậy?

Làm cách nào để thiết kế cách tích hợp vùng chứa IoC cho một tác vụ như vậy? (giả sử có nhiều điểm mở rộng, chẳng hạn như các sự kiện khác nhau có thể được sử dụng để đăng ký).

Một số câu hỏi tôi thấy mình hỏi:

  1. Có phổ biến mà các plugin tự đưa ra một Đăng ký phương pháp để làm việc đăng ký?
  2. IoC có nên đăng ký không? (thường được thực hiện như thế nào?)
  3. Làm cách nào để có thể dễ dàng xác định các điểm mở rộng khi sử dụng vùng chứa IoC?

Trả lời

5

Bạn có thể muốn xem MEF. Nó cho phép tất cả những điều bạn đã hỏi về. Thuật ngữ nó sử dụng (ComposableParts, Exports, vv) ban đầu là khó hiểu, nhưng nó rất dễ sử dụng.

Thông thường, bản thân plugin cung cấp phương thức Đăng ký để đăng ký ?

MEF làm cho ứng dụng thực hiện công việc tìm và đăng ký plugin. Plugin chỉ cần triển khai giao diện cho biết "Tôi là một plugin có thể thực hiện X".

IoC có nên đăng ký không? (thường được thực hiện như thế nào?)

Một ứng dụng sẽ tiêu thụ các plugin MEF có thể chỉ định cách nó sẽ tải các plugin. Điều này có thể bằng cách tìm kiếm một thư mục cho các tệp DLL, đọc tệp cấu hình cho một danh sách các tên assembly, kiểm tra GAC ​​- bất cứ điều gì cả. Nó hoàn toàn có thể mở rộng (trong đó bạn có thể viết các lớp tìm kiếm của riêng bạn)

Làm cách nào để dễ dàng xác định điểm mở rộng khi sử dụng hộp chứa IoC ?

MEF sử dụng giao diện để xác định Hợp đồng giữa ứng dụng và plugin.

+0

Với MEF, mỗi "phần" là một thực hiện một số giao diện. Điều này có nghĩa là đối với mỗi điểm mở rộng, một giao diện mới sẽ được tạo ra? Ví dụ, tôi có 3 sự kiện: OnA, OnB, OnC. Làm thế nào để tôi cho phép các plugin được nối vào các sự kiện này với MEF? (không định nghĩa 3 giao diện khác nhau). –

+0

Tôi không thực sự hiểu câu hỏi - nếu OnA, OnB và OnC được liên kết hợp lý theo cách mà chúng có thể hợp lý là một phần của một giao diện duy nhất làm cho chúng trở thành một giao diện duy nhất. Nếu chúng không được liên kết, hãy biến chúng trở thành một phần của các giao diện riêng biệt. Hay tôi đã hiểu lầm câu hỏi của bạn? –

+0

Ý tôi là, nếu tôi có nhiều sự kiện khác nhau mà tôi muốn đăng ký động, mỗi người trong số họ phải xác định rõ ràng họ đang nhập một giao diện nhất định. Điều này có nghĩa là tôi phải xác định 3 giao diện khác nhau (một cho mỗi loại sự kiện). Cho phép nói rằng tôi có 1 giao diện và 3 sự kiện để thực hiện giao diện này. Tất cả 3 sự kiện sẽ nhập tất cả các triển khai, đó không phải là những gì tôi theo sau. –

0

Câu trả lời này sẽ cụ thể cho vùng chứa của tôi.

Ứng dụng hiện tại của chúng tôi cần bắt đầu hỗ trợ tải động và "gắn" các "plugin"/"tiện ích" khác nhau mà ứng dụng không biết lúc biên dịch.

Để có thể thực hiện điều đó, bạn phải xác định một số giao diện tiện ích mở rộng mà bạn đặt trong thư viện lớp sẽ được chia sẻ giữa ứng dụng của bạn và tất cả các plugin của bạn.

Ví dụ, nếu bạn muốn ứng dụng của bạn để có thể thêm công cụ để áp dụng thực đơn bạn có thể tạo ra các giao diện sau:

class ApplicationMenu 
{ 
    // The "File" menu 
    IMenuItem File { get; } 
} 

interface IMenuRegistrar 
{ 
    void Register(ApplicationMenu menu); 
} 

Có nghĩa là plugin của bạn có thể tạo các lớp sau đây:

[Component] 
public class CoolPluginMenuRegistrar : IMenuRegistrar 
{ 
    public void Register(ApplicationMenu menu) 
    { 
     menu.File.Add("mnuMyPluginMenuName", "Load jokes"); 
    } 
} 

Thuộc tính [Component] được vùng chứa của tôi sử dụng để nó có thể khám phá và tự động đăng ký lớp học cho bạn.

Tất cả bạn cần làm gì để đăng ký tất cả các điểm mở rộng như trên là thế này:

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     var registrar = new ContainerRegistrar(); 
     registrar.RegisterComponents(Lifetime.Transient, Environment.CurrentDirectory, "MyApp.Plugin.*.dll"); 
     var container = registrar.Build(); 

     // all extension points have been loaded. To load all menu extensions simply do something like: 

     var menu = GetMainMenu(); 
     foreach (var registrar in container.ResolveAll<IMenuRegistrar>()) 
     { 
      registrar.Register(menu); 
     } 
    } 
} 

Những phần mở rộng sẽ là "móc" vào các khu vực khác nhau của ứng dụng, chẳng hạn như aded như xử lý sự kiện của một số lớp học. Từ kiến ​​thức của tôi, các container IoC cho phép tự động phát hiện các đối tượng trong thời gian chạy và đăng ký chúng trong một thùng chứa.

Đúng. Bạn nhận được tất cả điều đó.

Hộp chứa IoC có thể thực hiện thao tác này với các sự kiện khác nhau cho tôi không? Hoặc là nhiệm vụ này dễ dàng hơn để làm mà không có một khuôn khổ như vậy?

Có. Tôi có một cơ chế sự kiện được xây dựng sẵn. Đặt các lớp sự kiện (các lớp .NET thông thường trong các thư viện lớp học chung). Chỉ đơn giản là đăng ký trên chúng bằng cách thực hiện một giao diện:

[Component] 
public class ReplyEmailNotification : ISubscriberOf<ReplyPosted> 
{ 
    ISmtpClient _client; 
    IUserQueries _userQueries; 

    public ReplyEmailNotification(ISmtpClient client, IUserQueries userQueries) 
    { 
     _client = client; 
     _userQueries = userQueries; 
    } 

    public void Invoke(ReplyPosted e) 
    { 
     var user = _userQueries.Get(e.PosterId); 
     _client.Send(new MailMessage(user.Email, "bla bla")); 
    } 
} 

Và để công bố sự kiện:

DomainEvent.Publish(new ReplyPosted(user.Id, "This is a subject")); 

các sự kiện có thể được xử lý bởi bất kỳ plugin miễn là họ:

  1. thể truy cập lớp sự kiện
  2. Đã được đăng ký trong vùng chứa ([Component] hoặc đăng ký thủ công)
  3. .210
  4. Thực hiện ISubscriberOf<T>

Có phổ biến mà các plugin tự đưa ra một phương pháp Đăng ký để thực hiện đăng ký?

Đúng. Thông qua các giao diện khác nhau được định nghĩa là các điểm mở rộng trong một hội đồng chia sẻ.

IoC có nên đăng ký không? (thường được thực hiện như thế nào?)

Có. Nếu container cung cấp nó.

Làm cách nào để có thể dễ dàng xác định điểm mở rộng khi sử dụng vùng chứa IoC?

Bạn có thể đọc về nó một cách chi tiết hơn ở đây: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container

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