2010-04-23 29 views
6

Tôi muốn có một ứng dụng hoạt động như một Máy chủ lưu trữ cho nhiều ứng dụng nhỏ khác. Mỗi một trong các ứng dụng đó sẽ hoạt động như một loại plugin cho ứng dụng chính này. Tôi gọi chúng là các plugin không có nghĩa là chúng thêm một cái gì đó vào ứng dụng chính, nhưng vì chúng chỉ có thể làm việc với ứng dụng Máy chủ này vì chúng phụ thuộc vào một số dịch vụ của nó.Câu hỏi về cách triển khai ứng dụng máy chủ C# với kiến ​​trúc giống như plugin

Ý tưởng của tôi là để mỗi plugin trong số đó chạy trong miền ứng dụng khác. Vấn đề có vẻ là ứng dụng máy chủ của tôi nên có một bộ dịch vụ mà plugin của tôi sẽ muốn sử dụng và từ sự hiểu biết của tôi khiến luồng dữ liệu vào và ra từ các miền ứng dụng khác nhau không phải là điều tuyệt vời.

Một mặt tôi muốn chúng hoạt động như một ứng dụng độc lập (mặc dù, như tôi đã nói, chúng cần sử dụng nhiều lần dịch vụ ứng dụng máy chủ), nhưng mặt khác tôi muốn rằng bất kỳ lỗi nào trong số đó bị treo, ứng dụng chính của tôi sẽ không bị ảnh hưởng.

Cách tiếp cận tốt nhất (.NET) cho loại tình huống này là gì? Làm cho tất cả chúng chạy trên cùng một AppDomain nhưng mỗi một trong một chủ đề khác nhau? Sử dụng các AppDomain khác nhau? Một cho mỗi "plugin"? Làm cách nào để tôi liên lạc với Ứng dụng Máy chủ? Bất kỳ cách nào khác để làm điều này?

Mặc dù tốc độ không phải là vấn đề ở đây, tôi sẽ không thích cho các cuộc gọi hàm chậm hơn nhiều so với khi chúng tôi đang làm việc với một ứng dụng .NET thông thường.

Cảm ơn

EDIT: Có lẽ tôi thực sự cần phải sử dụng AppDomains khác nhau. Từ những gì tôi đã đọc, việc tải các assembly trong các AppDomain khác nhau là cách duy nhất để sau này có thể giải phóng chúng khỏi tiến trình.

Trả lời

5

Tôi đã triển khai điều gì đó dọc theo các dòng này bằng cách sử dụng Khung công cụ quản lý bổ trợ (MAF) trong không gian tên System.Addin. Với MAF bạn đóng gói các addins của bạn thành các file DLL riêng biệt, ứng dụng máy chủ của bạn có thể khám phá và khởi chạy trong miền ứng dụng của nó, trong một miền riêng biệt cho tất cả các addins, hoặc mỗi addin trong miền riêng của nó. Với bản sao bóng và các tên miền riêng biệt, bạn thậm chí có thể cập nhật một addin mà không cần tắt hostapp của bạn.

Ứng dụng máy chủ lưu trữ của bạn và giao diện người dùng giao tiếp thông qua các hợp đồng mà bạn lấy được từ các giao diện MAF. Bạn có thể gửi các đối tượng qua lại giữa máy chủ và các addins. Các cotnracts cung cấp một giao diện hộp đen giữa các addins và host, cho phép bạn thay đổi việc thực hiện của addin mà máy chủ không biết.

Addins thậm chí có thể giao tiếp với nhau nếu người tổ chức nói với họ về nhau. Trong trường hợp của tôi một addin đăng nhập được chia sẻ bởi những người khác. Điều này cho phép tôi thả các logger khác nhau mà không cần chạm vào các addins khác hoặc host.

Đối với ứng dụng của tôi, trình bổ sung sử dụng các lớp giám sát đơn giản trong các lớp nhân viên khởi chạy trên các chuỗi của riêng họ thực hiện tất cả quá trình xử lý. Người lao động bắt ngoại lệ của riêng họ, họ trở lại người giám sát của họ thông qua các phương thức gọi lại. Người giám sát có thể khởi động lại công nhân hoặc thực hiện hành động khác. Các máy chủ kiểm soát các giám sát thông qua một hợp đồng chỉ huy, mà chỉ thị cho họ để bắt đầu và ngừng công nhân và trả lại dữ liệu.

Ứng dụng máy chủ của tôi là dịch vụ Windows.Các chủ đề công nhân đã ném ngoại lệ cho tất cả các lý do thông thường (bao gồm cả lỗi!), Nhưng ứng dụng máy chủ chưa bao giờ gặp sự cố trong bất kỳ cài đặt nào của chúng tôi. Kể từ khi dịch vụ gỡ lỗi là bất tiện, addins cho phép tôi xây dựng các ứng dụng thử nghiệm sử dụng cùng một hợp đồng, với bảo đảm thêm rằng tôi đang thử nghiệm những gì tôi triển khai.

Addins cũng có thể hiển thị các phần tử giao diện người dùng. Điều này rất hữu ích với tôi khi tôi cần triển khai một ứng dụng điều khiển với dịch vụ lưu trữ, vì các dịch vụ không có giao diện người dùng. Mỗi plugin bao gồm giao diện điều khiển riêng của nó. Các ứng dụng điều khiển chính nó là rất đơn giản - nó tải các addins và hiển thị các yếu tố giao diện người dùng của họ. Điều này cho phép tôi gửi một addin cập nhật với một giao diện cập nhật và không phải gửi một bộ điều khiển mới.

Mặc dù bộ điều khiển và dịch vụ lưu trữ sử dụng cùng một phần bổ trợ, chúng không bước vào nhau; trên thực tế, họ thậm chí không biết rằng một ứng dụng khác đang sử dụng cùng một addins. Bộ điều khiển và máy chủ nói chuyện với nhau thông qua cơ sở dữ liệu được chia sẻ, nhưng bạn cũng có thể sử dụng một cơ chế liên ứng dụng khác như MSMQ. Trong phiên bản tiếp theo, máy chủ sẽ là một dịch vụ WCF với các addins trên các dịch vụ phụ trợ và web để kiểm soát.

Đây là một chút dài gió nhưng tôi muốn cung cấp cho bạn một ý tưởng về cách MAF linh hoạt. Nó không phức tạp như nó có thể nhìn đầu tiên, và bạn có thể xây dựng các ứng dụng vững chắc với nó.

1

Đây là câu hỏi liên tục. Ý tưởng đầu tiên của tôi là chỉ cần triển khai các giao diện từ ứng dụng máy chủ trong ứng dụng plugin của bạn để cho phép chúng giao tiếp thông qua Reflection, nhưng điều này chỉ cho phép giao tiếp và không mang kiến ​​trúc "sandbox-like" thực sự.

Suy nghĩ thứ hai của tôi là thiết kế nền tảng hướng dịch vụ. Ứng dụng máy chủ lưu trữ sẽ là một loại "trình phát plugin" sẽ xuất bản plugin của bạn trong ServiceHost trên một chuỗi khác. Vì điều này cần phải thực sự đáp ứng và "không có trí tuệ được cấu hình", ứng dụng máy chủ có thể giao tiếp với plugin thông qua kênh ống có tên (NetNamedPipesBinding for WCF) có nghĩa là chỉ giao tiếp với các đường ống cục bộ và không cần bất kỳ cấu hình mạng hoặc kiến ​​thức nào . Tôi nghĩ rằng đây có thể là một giải pháp tốt cho vấn đề của bạn.

Trân trọng.

2

Tùy thuộc vào mức độ tin cậy bạn muốn cho phép tiện ích mở rộng. Tôi đang làm việc trên một ứng dụng tương tự và tôi đã chọn chủ yếu là tin tưởng mã mở rộng, vì điều này đơn giản hóa rất nhiều thứ. Tôi gọi mã từ một luồng chung (trong trường hợp của tôi, các phần mở rộng không thực sự 'chạy' trong bất kỳ vòng lặp liên tục nào, mà là thực thi các tác vụ nhất định mà ứng dụng chính muốn) và bắt ngoại lệ trong chuỗi này, để cung cấp các cảnh báo hữu ích mà các tiện ích tải đã tải không đúng.

Hiện tại, không có gì giữ cho các tiện ích mở rộng này khởi chạy chủ đề của riêng chúng mà có thể ném và sụp đổ toàn bộ ứng dụng, nhưng điều này tôi đã phải cân bằng giữa sự an toàn và phức tạp. Ứng dụng của tôi không phải là nhiệm vụ quan trọng (không giống như một máy chủ web hoặc máy chủ cơ sở dữ liệu), vì vậy tôi coi đó là một nguy cơ chấp nhận được rằng một phần mở rộng lỗi có thể làm giảm ứng dụng của tôi.Tôi cung cấp biện pháp bảo vệ để lịch sự hơn bao gồm các trường hợp thất bại phổ biến nhất và để nó cho các nhà phát triển plugin (những người chủ yếu sẽ là người trong nhà cho bây giờ anyway) để làm sạch lỗi của họ.


Về việc dỡ tải, có, bạn chỉ có thể tải mã và siêu dữ liệu cho một hội đồng nếu bạn đặt nó trong một AppDomain. Điều đó nói rằng, trừ khi bạn muốn được tải và dỡ hàng thường xuyên trong suốt cuộc đời của chương trình của bạn, chi phí liên quan đến việc giữ mã trong bộ nhớ không nhất thiết là một vấn đề. Bất kỳ trường hợp hoặc tài nguyên thực tế nào sử dụng các kiểu từ assembly sẽ vẫn được làm sạch bởi GC khi bạn ngừng 'sử dụng' nó, vì vậy thực tế là nó vẫn còn trong bộ nhớ không có nghĩa là rò rỉ bộ nhớ.

Nếu trường hợp sử dụng chính của bạn là một loạt các plugin mà bạn định vị khi khởi động và sau đó cung cấp tùy chọn để khởi tạo trong khi ứng dụng của bạn đang chạy, tôi đề nghị điều tra bộ nhớ thực liên quan đến việc tải tất cả chúng khi khởi động và giữ chúng được tải. Nếu bạn sử dụng AppDomains, sẽ có phí bổ sung ở đó (ví dụ, bộ nhớ cho các đối tượng proxy và mã được nạp/JITed để hỗ trợ marshaling AppDomain). Cũng sẽ có chi phí CPU liên quan đến việc tuần tự hóa và tuần tự hóa.

Nói tóm lại, tôi sẽ chỉ sử dụng AppDomains nếu một trong những điều sau đây là đúng:

  • Tôi muốn để có được cách ly đúng đối với các mục đích an ninh mã (tức là tôi cần phải chạy mã không tin cậy trong một biệt lập theo cách này)

  • Ứng dụng của tôi là nhiệm vụ quan trọng và tôi hoàn toàn cần đảm bảo rằng nếu plugin không thành công, ứng dụng này không thể gỡ ứng dụng cốt lõi của tôi xuống.

  • Tôi cần tải và tải cùng một plugin nhiều lần, để hỗ trợ thay đổi động cho DLL. Điều này chủ yếu là nếu ứng dụng của tôi không thể ngừng chạy, nhưng tôi muốn các plugin cập nhật nóng trong khi ứng dụng vẫn chạy.

Tôi không thích AppDomains với mục đích duy nhất là giảm dung lượng bộ nhớ có thể bằng cách cho phép Unload.

+0

Đây là một ứng dụng sở thích, không có gì đặc biệt. Tôi hoàn toàn tin tưởng chạy mã. Vấn đề là tôi cần mỗi một plugin của tôi để chạy tất cả thời gian (nghĩa là tôi không thể chỉ làm cho ứng dụng máy chủ của tôi gọi các plugin của tôi, chúng phải độc lập và tự chạy.) –

+1

Trong trường hợp đó, tôi chỉ cần cung cấp mỗi Chủ đề của riêng họ chạy vào và gọi bất kỳ phương thức 'Chính' nào bạn đã xác định. Bạn có thể chọn để bọc cuộc gọi đến 'Chính' từ chuỗi trong một lần thử/nắm bắt nếu bạn muốn cung cấp dự phòng thân thiện trong trường hợp một plugin ném ngoại lệ. –

+0

Có, nhưng xem chỉnh sửa ở trên. Bằng cách đó, sau này tôi không thể tải các assembly được nạp mà không cần khởi động lại ứng dụng. Tôi phải có chúng trong các miền ứng dụng khác nhau để tôi có thể dỡ chúng bất cứ khi nào tôi muốn. –

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