Використання розширень MVC HtmlHelper з декларативних поглядів Razor


121

Я намагався створити декларативний помічник Razor у своїй папці App_Code для проекту MVC 3 RTM.

Проблема, з якою я зіткнувся, полягала в тому, що розширення MVC HtmlHelper, як і ActionLink, недоступні. Це пояснюється тим, що складені помічники походять від System.Web.WebPages.HelperPage, і хоч це викриває Htmlвластивості, System.Web.WebPages.HtmlHelperа не типу System.Web.Mvc.HtmlHelper.

Приклад помилки, яку я отримував:

'System.Web.Mvc.HtmlHelper' не містить визначення для 'ActionLink', і жодного методу розширення 'ActionLink', що приймає перший аргумент типу 'System.Web.Mvc.HtmlHelper', не вдалося знайти (ви не пропускаєте використання директиви або посилання на збірку?)

Моє єдине рішення - створити власну HelperPage та змінити властивість 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; }
    }
}

Тоді я повинен написати наступне у верхній частині кожного помічника:

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

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

Чи означає це бути таким важким у MVC 3, чи я щось роблю не так?


4
Якщо вам також потрібен помічник Url, вам слід додати цей рядок коду до HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Марко Штафтолі

Відповіді:


42

Подивіться на Marcindвідповідь на це питання. Те, що у вас виникає, є обмеженням розміщення декларативних поглядів у App_Codeпапці.

Розміщення помічників у App_Code працює, але має певні обмеження, які впливають на певні сценарії MVC (наприклад: відсутність доступу до стандартних MVC Html. Помічників)


1
Зауважте іншим читачам: ця відповідь абсолютно правильна, але також ознайомтесь із додатковим внеском Ендрю Медсестри нижче щодо можливого вирішення.
Джордан Сірий

38

Я створив метод розширення для помічника WebPages, щоб я міг отримати доступ до помічника сторінки.

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

4
Використання:@Html.GetPageHelper().ActionLink("actioname")
deerchao

Це працює для мене, але я повинен був додати @using System.Web.Mvcі @using System.Web.Mvc.Htmlв cshtml хелперів файл всередині App_Code
Tomino

1
Чому існує окремий клас HtmlHelper? Він повинен бути таким же, будь то в App_Code або Переглядах. Епічний напівзапроваджений дизайн провалюється.
Трайнко

Тут посилається weblogs.asp.net/scottgu/…, що робить хорошу роботу, описуючи, як створити "глобальних" помічників Razor. Тож, якщо вам потрібен лише HtmlHelperклас для цілей кодування, я знайшов ще швидший спосіб зробити це за допомогою статичного класу, Microsoft.Security.Application.Encoderяк у:Encoder.HtmlAttributeEncode(value)
Matt Borja

11

Омар отримав правильну відповідь тут, але я хотів щось додати (не соромтесь позначити відповідь Омара як відповідь).

Ми знали про це в v1 і не змогли отримати чудову корекцію продукту, але Девід Еббо (архітектор команди ASP.Net) опублікував зразок Visual Studio Generator Code, який в основному є першим дослідженням які ідеї ми розглядаємо, щоб зробити цю роботу належним чином: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Спробуйте це і подивіться, що ви думаєте! Повідомте Девіда, якщо у вас є коментарі, розмістивши його в своєму блозі.


2
Чи планується це виправити в наступній версії Razor? Я помітив, що це все ще проблема в VS 11 Beta.
Омар

9

Схожа на відповідь @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; }
    }

}

Використання:

@MvcIntrinsics.Html.Raw("test")

Джерело: Dino Esposito - Програмування Microsoft ASP.NET MVC


1
Смішно, що це навіть потрібно, і що вони не просто частина базового класу для переглядів у App_Code.
Трайнко

7

Альтернативне рішення:

Додайте це зверху до свого файлу-помічника:

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

тоді назвіть це так:

@HHtml.ActionLink("actionname")

Це виглядало так, що це спрацювало для мене спочатку, але при повторному виклику помічника я отримав "значення не входить у очікуваний діапазон".
d219

3

Мій підхід до цього полягає в тому, щоб просто передати сторінку як параметр до хелперного методу. Так у вашому прикладі це було б:

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

Тоді у вашому представленні бритва, де вам це потрібно, називайте так:

@YourHelperFilename.DoSomething(this)

Це негайно дає вам доступ до таких властивостей сторінки, як Htmlі Urlякі ви зазвичай маєте (і через це HtmlHelperрозширення).

В якості додаткової переваги (якщо цього потрібно) ви також отримуєте доступ до властивостей екземпляра, таких як сторінки ViewData.


3

На користь пошуків я отримав таку ж помилку під час створення MVC-переглядів як частини бібліотеки класів (для повторного використання компонентів). Рішення, частково нагадане вище, полягало в тому, щоб додати наступне за допомогою операторів у верхній частині файлу .cshtml:

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

Більше не потрібно працювати.


Мої помічники в моєму .cshtml під App_Code не були розпізнані в Intellisense. Додано @using System.Web.Mvc.Html у верхній частині мого .cshtml у розділі App_code.

Коли я це роблю, я отримую, "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."коли ширяє @using System.Web.Mvc. Будь-які ідеї?
JoeBrockhaus

Це не має ніякого значення для мене
MEMS

0

Я знаю, що з MVC 3. є деякі проблеми з інтелігенцією. Я думаю, що помічники все ще працюватимуть, якщо у вас буде встановлено простір імен в web.config.

MVC 3 RTM щойно вийшов, використовуєте ви це чи бета-версію?


0

Схоже, ASP.NET MVC виправив цю проблему у VS 2013. Дивіться цю публікацію http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht


Ні, зовсім не. Intellisense не підбирає методи розширення, і у мене є оновлення VS2013 5. У мене @using System.Web.Mvc.Htmlвгорі файлу cshtml у App_Code, але написання @Html .... не виявляє жодного з методів розширення, таких як EditorFor. Смішно, що це не працює після двох основних випусків та публікацій у блогах, у яких стверджується, що це було здійснено. Це не. Насправді, способи розширення не можуть працювати, оскільки вони націлені на клас System.Web.Mvc.HtmlHelper, а не на клас System.Web.WebPages.HtmlHelper, який піддається класу System.Web.WebPages.HelperPage.
Трайко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.