2012-02-08 32 views
5

Tôi đang sử dụng các khung nhìn Razor được biên dịch trong các thư viện lớp riêng biệt như một loại hệ thống plugin cho MVC3.MVC3 - Chế độ xem dao cạo được biên dịch không thể tìm thấy _ViewStart

Tôi đã làm theo hướng dẫn của Chris Van De Steed here và chỉ bị lệch phần lớn về phần bổ sung tài liệu tham khảo, khi tôi đang tải các assembly của mình khi chạy.

Vì tôi đang tải các hội đồng vào thời gian chạy, tôi không sử dụng VirtualPathProviderViewEngine trong thư viện BoC và thay vào đó đã triển khai ViewEngine của riêng mình dựa trên RazorViewEngine. Nó hoạt động bằng cách viết lại viewPath trong CreateView để chèn không gian tên thích hợp để khung nhìn có thể được giải quyết.

Cho đến nay rất tốt ... Tôi có thể tải các mô-đun khác nhau và bộ điều khiển của chúng sẽ không xung đột nếu chúng có cùng tên.

Vấn đề duy nhất tôi có bây giờ là cho chế độ xem được biên dịch, _ViewStart không được gọi. _ViewStart hoạt động cho các khung nhìn trong dự án MVC3 host, nhưng đối với bất kỳ khung nhìn nào được nạp từ các assembly plugin thì nó không được tìm thấy.

Tôi có một thiết lập Route như thế này: -

RouteTable.Routes.MapRoute(
    string.Format("Plugin{0}Route", pluginName), 
    string.Format(@"Plugin/{0}/{{controller}}/{{action}}", pluginName), 
    new { }, 
    new string[] { string.Format("{0}.Controllers", pluginName) }); 

các ViewEngine trông như thế này: -

public class PluginRazorViewEngine : RazorViewEngine 
{ 
    public PluginRazorViewEngine() : base() 
    { 
     ViewLocationFormats = new[] 
     { 
      "~/Plugin/%1/Views/{1}/{0}.cshtml", 
      "~/Plugin/%1/Views/{1}/{0}.vbhtml", 
      "~/Plugin/%1/Views/Shared/{0}.cshtml", 
      "~/Plugin/%1/Views/Shared/{0}.vbhtml", 
      "~/Views/{1}/{0}.cshtml", 
      "~/Views/{1}/{0}.vbhtml", 
      "~/Views/Shared/{0}.cshtml", 
      "~/Views/Shared/{0}.vbhtml" 
     }; 

(% 1 được thay thế bằng tên của hội đồng)

và lắp ráp được đăng ký với thư viện BoC như sau: -

BoC.Web.Mvc.PrecompiledViews.ApplicationPartRegistry.Register(assembly, string.Format("/Plugin/{0}/", pluginName)); 

Khi chế độ xem được tải từ một hội đồng plugin (trong ví dụ này "tài khoản"), giao diện được tìm thấy và hiển thị OK. Nhưng sau đó nó sẽ tìm trong các địa điểm này cho _ViewStart: -

~/plugin/accounts/views/invoice/_viewstart.cshtml 
~/plugin/accounts/views/invoice/_viewstart.vbhtml 
~/plugin/accounts/views/_viewstart.cshtml 
~/plugin/accounts/views/_viewstart.vbhtml 
~/plugin/accounts/_viewstart.cshtml 
~/plugin/accounts/_viewstart.vbhtml 
~/plugin/_viewstart.cshtml 
~/plugin/_viewstart.vbhtml 
~/_viewstart.cshtml 
~/_viewstart.vbhtml 

Nhưng nó không nhìn vào ~/Views/Shared/_ViewStart.cshtml nơi cuộc sống tập tin.

Tôi đã thử thay đổi tất cả các định dạng vị trí trong ViewEngine của tôi (AreaMasterLocationFormats, AreaPartialViewLocationFormats, AreaViewLocationFormats, MasterLocationFormats, PartialViewLocationFormats và ViewLocationFormats) nhưng không có định dạng nào trong số chúng có vẻ khác biệt.

Tôi đã xem xét và dường như System.Web.WebPages.StartPage.GetStartPage chịu trách nhiệm tìm và trả lại trang bắt đầu trong chế độ xem, nhưng tôi không thể tìm thấy bất kỳ thông tin nào về cách kiểm soát vị trí của trang.

tôi đã cố gắng di chuyển _ViewStart.cshtml tới ~/_ViewStart.cshtml (một trong những nơi có vẻ) tuy nhiên tôi ngay lập tức nhận được: -

Unable to cast object of type 'ASP._Page__ViewStart_cshtml' to type 'System.Web.WebPages.StartPage'. 

Mà theo những gì tôi đã đọc, là vì _ViewStart cần phải sống dưới/Lượt xem

Tôi có thể sửa đổi nơi MVC tìm kiếm _ViewStart không?

Thư viện Bộc thực hiện nó IView riêng, và kêu gọi như sau: -

startPage = this.StartPageLookup(page, VirtualPathFactoryManagerViewEngine.ViewStartFileName, this.ViewStartFileExtensions); 

Nhưng trong trường hợp này ViewStartFileName chỉ là "_ViewStart" và ViewStartFileExtensions chỉ cshtml và vbhtml ... không có gì đó sẽ kiểm soát nơi MVC nên tìm kiếm tệp.

Trả lời

1

một ý tưởng ... (như trong, đã không thử nó nó sẽ không hoạt động ý tưởng.?)

có lẽ có một cái nhìn tại kế thừa từ RazorView (hoặc thay thế nó hoàn toàn, xem xét - như chúng tôi sẽ xem - y bạn sẽ viết lại một phương thức là phần lớn của lớp).

RazorView là nơi StartPage.GetStartPage được giới thiệu bằng cách gán nó vào một tài sản StartPageLookup:

// In RazorView constructor: 
StartPageLookup = StartPage.GetStartPage; 

Thật không may, rằng bất động sản đại biểu là nội bộ, vì vậy bạn có thể không chỉ ghi đè lên nó trong nguồn gốc lớp constructor của bạn. Bạn có thể, tuy nhiên, có thể ghi đè RazorView.RenderView, đó là nơi nó sử dụng (mã nguồn MVC3, rất nhiều dòng loại bỏ, dòng-chia bổ sung của tôi):

protected override void RenderView(ViewContext viewContext, TextWriter writer, 
    object instance) 
{ 
    // [SNIP] 

    WebPageRenderingBase startPage = null; 
    if (RunViewStartPages) { 
    // HERE IT IS: 
    startPage = StartPageLookup(
     webViewPage, 
     RazorViewEngine.ViewStartFileName, 
     ViewStartFileExtensions 
    ); 
    } 
    webViewPage.ExecutePageHierarchy(
    new WebPageContext(
     context: viewContext.HttpContext, 
     page: null, 
     model: null), 
    writer, startPage); 
} 

Thay thế mà StartPageLookup cuộc gọi với của riêng bạn tra cứu, sau đó thay thế kết quả của CreateViewCreatePartialView trong số PluginRazorViewEngine bằng lớp PluginRazorView mới của bạn.

+0

Tôi đã làm như bạn đã đề xuất và tạo "PluginRazorView" của riêng mình kế thừa từ RazorView. Tôi phải ghi đè lên RenderView như bạn đã đề xuất và tôi đã cố gắng sao chép phương thức MVC GetStartPage và chỉ thêm logic của riêng tôi để tìm kiếm các đường dẫn bổ sung, tuy nhiên đó là một mìn của nội bộ và phản chiếu. chứng minh rằng nó hoạt động và tôi sẽ phải làm sạch nó sau này. Thật thú vị khi họ đã sử dụng một đại biểu ở đây ... có vẻ như các phương pháp tìm kiếm khác nhau có thể được sử dụng, nhưng không có cách nào để chỉ định chúng. Rất cám ơn sự giúp đỡ. – Aleks

+0

Vâng, đó là những gì tôi nghĩ quá. Giống như bạn nói, họ đang sử dụng một đại biểu để cho phép thay đổi phương pháp tra cứu, nhưng sau đó khai báo nó 'nội bộ', do đó, nó chỉ là không gian tên Mvc mà thực sự có thể thay đổi nó ... – JimmiTh

1

Vì vậy, để trả lời câu hỏi của riêng tôi ... nó có vẻ như không có, bạn không thể sửa đổi nơi MVC trông cho _ViewStart ...

Nhìn vào nguồn gốc của System.Web.WebPages.StartPage. GetStartPage (mà tôi nhận được từ here) Tôi có thể thấy rằng nó chỉ đi qua đường dẫn từ trang gọi đến tận gốc và dường như không có cách nào để kiểm soát hành vi này (nghĩa là nó được mã hóa cứng trong System.Web.WebPages.StartPage)

Trong trường hợp bình thường (ví dụ bố trí chuẩn MVC3) điều này sẽ ổn ... tất cả các khung nhìn nằm trong/Views và tệp _ViewStart chính sẽ được đánh giá khi GetStartPage đạt tới nó.

Vì vậy, những gì tôi đã làm cơ bản là phá vỡ chức năng này bằng cách di chuyển các khung nhìn của tôi ra khỏi hệ thống phân cấp thư mục/Views. Tôi đoán điều này có nghĩa là tôi có thể di chuyển tệp _ViewStart của mình vào vị trí mà nó sẽ được tìm thấy (loại phá vỡ mục tiêu dự định của tôi là có một _ViewStart chung cho tất cả các plugin của tôi) hoặc tìm ra cách viết lại/re-directing về các yêu cầu cho _ViewStart trong phân cấp đó đến đúng tệp trong/Views/Shared/_ViewStart (không rõ ràng ngay với tôi).

Điều thú vị là mã MVC3 sẽ tìm _ViewStart trong /, dựa trên những gì tôi đã đọc sẽ không hoạt động, dẫn đến "Không thể truyền đối tượng kiểu 'ASP. Trang _ViewStart_cshtml' loại 'System.Web.WebPages.StartPage' "lỗi (mặc dù tôi nghi ngờ điều này là chỉ vì mặc định/web.config không có các công cụ cần thiết trong nó để phân tích cú pháp đúng các tập tin, trong khi /Views/web.config không)

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