11

Tôi đang xây dựng một ứng dụng MVC 3 trong đó MEF được sử dụng. Ý tưởng chính là có cơ chế plug-in, nơi các mô hình, bộ điều khiển và khung nhìn được nạp động trong suốt thời gian chạy từ container mef.MEF và MVC 3 - cách tải chế độ xem được nhúng động từ vùng chứa mef?

Mỗi plugin/mô-đun bao gồm hai cụm:

  • Module1.Data.dll (chứa các định nghĩa của các mô hình)
  • Module1.Web.dll (chứa bộ điều khiển và quan điểm)

và được đưa vào thư mục Plugins bên trong thùng ứng dụng web:

  • WebApp/Bin/Plugins/Module1.Data.dll
  • WebApp/Bin/Plugins/Module1.Web.dll
  • WebApp/Bin/Plugins/Module2.Data.dll
  • WebApp/Bin/Plugins/Module2.Web.dll
  • WebApp/Bin/Plugins /ModuleCore.Data.dll
  • WebApp/Bin/Plugins/ModuleCore.Web.dll
  • vv ...

Ngoài ra còn có mô-đun lõi mà được tham chiếu bởi tất cả các module khác: ModuleCore.Data. dll và tương ứng ModuleCore.Web.dll.

Sau đó, trong Global.asax, container là xây dựng theo cách sau:

AggregateCatalog catalog = new AggregateCatalog(); 
var binCatalog = new DirectoryCatalog(HttpRuntime.BinDirectory, "Module*.dll"); 
var pluginsCatalot = new DirectoryCatalog(Path.Combine(HttpRuntime.BinDirectory, "Plugins"), "Module*.dll"); 
catalog.Catalogs.Add(binCatalog); 
catalog.Catalogs.Add(pluginsCatalot); 
CompositionContainer container = new CompositionContainer(catalog); 
container.ComposeParts(this); 
AppDomain.CurrentDomain.AppendPrivatePath(Path.Combine(HttpRuntime.BinDirectory, "Plugins")); 

CustomViewEngine được tạo ra và đã đăng ký và sử dụng cho quan điểm tìm trong lắp ráp mô-đun:

ViewEngines.Engines.Clear(); 
ViewEngines.Engines.Add(new CustomViewEngine()); 

điều khiển nhà máy để tải bộ điều khiển từ vùng chứa:

ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(_container)); 

và cũng cung cấp tùy chỉnh ảo đường cho việc lắp ráp từ container:

HostingEnvironment.RegisterVirtualPathProvider(new ModuleVirtualPathProvider()); 

Ok, do đó toàn bộ cơ sở hạ tầng để xử lý mô hình pluggable, bộ điều khiển và quan điểm sẵn sàng. Bây giờ mọi thứ hoạt động ... ngoại trừ một điều - chế độ xem được nhập mạnh mẽ.

Để ilustrate vấn đề chi tiết hơn, chúng ta hãy chuẩn bị các cảnh:

  • mô hình UserDTO tọa lạc tại Module1.Data.dll
  • ShowUserController.cs tọa lạc tại Module1.Web.dll/controllers/
  • Index.cshtml nằm trong Module1.Web.dll/Views/ShowUser (có khai báo @model Module1.Data.UserDto)

Bây giờ chúng ta làm như sau:

  1. Chạy ứng dụng và đi đến HOST/ShowUser/Index (phương thức action Index được thực thi trên ShowUserController và xem Index.cshtml được nạp)
  2. Sau khi xem Index.cshtml được tìm nạp - bắt đầu biên dịch (bởi RazorBuildProvider)
  3. Ngoại lệ: "không thể tìm thấy kiểu dữ liệu trong không gian tên Module1", nói cách khác UserDTO không thể tìm thấy trong khi xây dựng chế độ xem động

Vì vậy, có vẻ như trình biên dịch/người xây dựng không nhìn qua thư mục bin/Plugins cho Module1.Data.dll, bởi vì khi tôi sao chép tệp này vào thư mục bin - nó được viết tốt.

Câu hỏi/vấn đề: tại sao builder không nhìn vào thư mục bin/Plugins mặc dù thư mục này đã được bổ sung bằng phương pháp AppDomain.CurrentDomain.AppendPrivatePath? Làm thế nào để thêm đường dẫn riêng cho người xây dựng lắp ráp một lần để thư mục plugins sẽ được xem xét?

Tôi đã cố gắng để làm một số công việc xung quanh bằng cách tạo CustomRazorBuildProvider đó sẽ ghi đè chuẩn một:

public class CustomRazorBuildProvider : RazorBuildProvider 
{ 
    public override void GenerateCode(System.Web.Compilation.AssemblyBuilder assemblyBuilder) 
    { 
    Assembly a = Assembly.LoadFrom(Path.Combine(HttpRuntime.BinDirectory, "Plugins", "Module1.Data.dll")); 
    assemblyBuilder.AddAssemblyReference(a);  
    base.GenerateCode(assemblyBuilder); 
    } 
} 

nhưng nhược điểm của giải pháp này là mọi quan điểm được biên dịch, tài liệu tham khảo cho tất cả các hội đồng trong thư mục Plugins cần được thêm vào, điều này có thể gây ra các vấn đề về hiệu suất sau này khi nhiều plugin sẽ được sử dụng.

Bất kỳ giải pháp đẹp hơn nào?

+2

Bạn đã bao giờ giải quyết vấn đề này chưa? Tôi đang cố gắng giải quyết vấn đề tương tự với ứng dụng MVC của tôi vào lúc này. Bạn có bất kỳ nguồn nào đang chạy mà tôi có thể xem được không? – Coppermill

+1

Có, tôi đã giải quyết nó bằng CustomRazorBuildProvider như được mô tả ở trên. Hovewer kể từ thời điểm đó, ứng dụng của chúng tôi là nhận được nhiều hơn vào cách tiếp cận MVVM, nơi ít xem dao cạo được sử dụng, và xem html/javascript tinh khiết hơn được xây dựng. – untoldex

Trả lời

1

Đây là suy nghĩ.

Nếu bạn làm theo Mẫu mô hình xem thì thay vì gửi thẳng DTO đến chế độ xem, hãy sử dụng ViewModel sẽ nằm trong cùng một cụm như Chế độ xem.

Vì vậy, thay vì:

mô hình UserDTO

tọa lạc tại Module1.Data.dll ShowUserController.cs tọa lạc tại Module1.Web.dll/controllers/ Index.cshtml tọa lạc tại Module1.Web.dll/views/ShowUser (với tuyên bố @model Module1.Data.UserDto)

Bạn sẽ có:

mô hình UserDTO tọa lạc tại Module1.Data.dll ShowUserController.cs tọa lạc tại Module1.Web.dll/Bộ xử lý/ UserVM nằm trong Module1.Web.d ll/ViewModels Index.cshtml tọa lạc tại Module1.Web.dll/Views/ShowUser (với tuyên bố @model Module1.Web.ViewModels.UserVM)

Có Map DTO của bạn để ViewModels khiển

Xem AutoMapper để trợ giúp với Ánh xạ

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