Sử dụng tiện ích mở rộng MVC HtmlHelper từ các chế độ xem so sánh Razor


121

Tôi đang cố gắng tạo trình trợ giúp khai báo Razor trong thư mục App_Code của mình cho dự án MVC 3 RTM.

Vấn đề tôi gặp phải là các tiện ích mở rộng MVC HtmlHelper, như ActionLink, không khả dụng. Điều này là do các trình trợ giúp được biên dịch bắt nguồn từ System.Web.WebPages.HelperPage, và mặc dù nó hiển thị một thuộc Htmltính, nhưng loại của nó System.Web.WebPages.HtmlHelperthay vì System.Web.Mvc.HtmlHelper.

Một ví dụ về loại lỗi tôi gặp phải là:

Có thể tìm thấy 'System.Web.Mvc.HtmlHelper' không chứa định nghĩa cho 'ActionLink' và không có phương thức mở rộng nào 'ActionLink' chấp nhận đối số đầu tiên của loại 'System.Web.Mvc.HtmlHelper' (bạn có thiếu chỉ thị using hay một tham chiếu lắp ráp?)

Giải pháp duy nhất của tôi là tạo HelperPage của riêng tôi và ghi đè thuộc tính Html:

using System.Web.WebPages;

public class HelperPage : System.Web.WebPages.HelperPage 
{
    // Workaround - exposes the MVC HtmlHelper instead of the normal helper
    public static new HtmlHelper Html
    {
        get { return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html; }
    }
}

Sau đó, tôi phải viết những điều sau ở đầu mỗi người trợ giúp:

@inherits FunnelWeb.Web.App_Code.HelperPage
@using System.Web.Mvc
@using System.Web.Mvc.Html

@helper DoSomething()
{
    @Html.ActionLink("Index", "Home")
}

Nó có nghĩa là khó đến mức này trong MVC 3, hay tôi đã làm sai điều gì đó?


4
Nếu bạn cũng cần trình trợ giúp Url, bạn nên thêm dòng mã này vào HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Câu trả lời:


42

Hãy xem Marcindcâu trả lời của câu hỏi này. Những gì bạn đang gặp phải là một hạn chế của việc đưa các chế độ xem khai báo vào App_Codethư mục.

Việc đưa trình trợ giúp của bạn vào App_Code hoạt động nhưng có một số hạn chế nhất định ảnh hưởng đến một số trường hợp MVC nhất định (ví dụ: không có quyền truy cập vào MVC Html tiêu chuẩn. Helpers)


1
Lưu ý với các độc giả khác: câu trả lời này hoàn toàn đúng, nhưng cũng hãy xem phần đóng góp bổ sung của Andrew Nurse bên dưới để biết cách giải quyết tiềm năng.
Jordan Grey

38

Tôi đã tạo một phương thức mở rộng cho trình trợ giúp Trang web để tôi có thể truy cập vào trình trợ giúp trang.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}

4
Cách sử dụng:@Html.GetPageHelper().ActionLink("actioname")
hươu sao vào

Điều này phù hợp với tôi, nhưng tôi phải thêm @using System.Web.Mvc@using System.Web.Mvc.Htmlvào tệp trợ giúp cshtml bên trong App_Code
Tomino

1
Tại sao có lớp HtmlHelper riêng biệt? Nó phải giống nhau cho dù là trong App_Code hay Views. Thiết kế được triển khai một nửa sử thi không thành công.
Triynko

Đã được giới thiệu tại đây bởi weblogs.asp.net/scottgu/…. Trang này thực hiện rất tốt việc mô tả cách tạo trình trợ giúp Razor "toàn cầu". Vì vậy, sau đó, nếu bạn chỉ cần HtmlHelperlớp để mã hóa các mục đích, tôi thấy một cách thậm chí nhanh hơn để làm điều này là thông qua các lớp tĩnh Microsoft.Security.Application.Encodernhư trong:Encoder.HtmlAttributeEncode(value)
Matt Borja

11

Omar có câu trả lời đúng ở đây, nhưng tôi muốn bổ sung thêm điều gì đó (đừng ngại đánh dấu câu trả lời của Omar là câu trả lời).

Chúng tôi đã biết điều này trong phiên bản v1 và không thể có được bản sửa lỗi tuyệt vời trong sản phẩm, nhưng David Ebbo (một kiến ​​trúc sư trong nhóm ASP.Net) đã đăng một mẫu Trình tạo mã Visual Studio về cơ bản là khám phá đầu tiên về loại ý tưởng mà chúng tôi đang xem xét để làm cho điều này hoạt động bình thường: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Hãy thử điều đó và xem bạn nghĩ gì! Hãy cho David biết nếu bạn có nhận xét bằng cách đăng trên blog của anh ấy.


2
Có kế hoạch sửa lỗi này trong phiên bản tiếp theo của Razor không? Tôi nhận thấy đây vẫn là một vấn đề trong VS 11 Beta.
Omar

9

Tương tự với câu trả lời @Jakes:

public static class MvcIntrinsics {
    public static System.Web.Mvc.HtmlHelper Html {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html; }
    }

    public static System.Web.Mvc.AjaxHelper Ajax {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Ajax; }
    }

    public static System.Web.Mvc.UrlHelper Url {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Url; }
    }

}

Sử dụng:

@MvcIntrinsics.Html.Raw("test")

Nguồn: Dino Esposito - Lập trình Microsoft ASP.NET MVC


1
Thật nực cười khi điều này thậm chí còn cần thiết và đây không chỉ là một phần của lớp cơ sở cho các khung nhìn trong App_Code.
Triynko

7

Một giải pháp thay thế:

Thêm cái này vào đầu tệp trợ giúp dao cạo của bạn:

@functions {
    public static System.Web.Mvc.HtmlHelper<object> HHtml = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html;
}

sau đó gọi nó như thế này:

@HHtml.ActionLink("actionname")

Điều này có vẻ như ban đầu nó hoạt động với tôi nhưng khi gọi lại người trợ giúp, tôi nhận được 'giá trị không nằm trong phạm vi mong đợi'.
d219

3

Cách tiếp cận của tôi là chỉ cần chuyển trang dưới dạng tham số cho phương thức trợ giúp. Vì vậy, trong ví dụ của bạn, nó sẽ là:

@helper DoSomething(WebViewPage page)
{
    @page.Html.ActionLink("Index", "Home")
}

Sau đó, trong chế độ xem Razor của bạn, nơi bạn cần nó gọi nó như thế này:

@YourHelperFilename.DoSomething(this)

Làm điều này ngay lập tức cung cấp cho bạn quyền truy cập vào các thuộc tính trang giống như Htmlhoặc Urlmà bạn thường có (và thông qua đó là các HtmlHelperphần mở rộng).

Như một lợi ích bổ sung (nếu bạn yêu cầu điều này), bạn cũng có quyền truy cập vào các thuộc tính cá thể như của trang ViewData.


3

Vì lợi ích của người tìm kiếm, tôi đã gặp lỗi tương tự khi tạo chế độ xem MVC như một phần của thư viện lớp (để sử dụng lại thành phần). Giải pháp, một phần được đề cập ở trên, là thêm các câu lệnh sau bằng cách sử dụng ở đầu tệp .cshtml:

@using System.Web.Mvc
@using System.Web.Mvc.Html

Không cần làm thêm.


Những người trợ giúp trong .cshtml của tôi trong App_Code không được công nhận trong Intellisense. Thêm @using System.Web.Mvc.Html ở đầu .cshtml của tôi trong App_code đã hoạt động.

Khi tôi làm điều này, tôi nhận được "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."khi di chuột @using System.Web.Mvc. Có ý kiến ​​gì không?
JoeBrockhaus

Điều đó không có gì khác biệt đối với tôi
mems

0

Tôi biết rằng có một số vấn đề phức tạp với MVC 3. Tôi nghĩ rằng trình trợ giúp sẽ vẫn hoạt động nếu bạn đặt không gian tên trong web.config.

MVC 3 RTM vừa được bán lại bạn đang sử dụng bản này hay bản beta?


0

Có vẻ như ASP.NET MVC đã khắc phục sự cố này trong VS 2013. Xem bài đăng này http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht


Không phải là tất cả. Intellisense không chọn các phương thức mở rộng và tôi có bản cập nhật VS2013 5. Tôi có @using System.Web.Mvc.Htmlở đầu tệp cshtml trong App_Code, nhưng việc viết @Html .... không tiết lộ phương thức mở rộng nào như EditorFor. Thật tuyệt vời khi điều này không hoạt động sau 2 bản phát hành chính và các bài đăng trên blog tuyên bố rằng nó đã được triển khai. Nó không thể. Trên thực tế, các phương thức mở rộng không thể hoạt động, vì chúng nhắm mục tiêu đến lớp System.Web.Mvc.HtmlHelper, không phải lớp System.Web.WebPages.HtmlHelper, được hiển thị bởi lớp System.Web.WebPages.HelperPage.
Triynko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.