Использование расширений MVC HtmlHelper из декларативных представлений Razor

Я пытался создать декларативный помощник Razor в папке App_Code для проекта RTM MVC 3.

Проблема, с которой я столкнулся, заключалась в том, что расширения 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, или я делаю что-то неправильно?

Ответ 1

Посмотрите Marcind ответ на этот вопрос. То, что вы испытываете, - это ограничение размещения декларативных представлений в папке App_Code.

Использование ваших помощников в App_Code но имеет определенные ограничения, которые влияют на некоторые сценарии MVC (для пример: нет доступа к стандартному MVC Html. хелперов)

Ответ 2

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

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

Ответ 3

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

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

Попробуй это и посмотри, что ты думаешь! Пусть Давид узнает, есть ли у вас комментарии, разместив в своем блоге.

Ответ 4

Подобно @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

Ответ 5

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

Добавьте это поверх своего файла-бритвы-хелпера:

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

затем назовите его следующим образом:

@HHtml.ActionLink("actionname")

Ответ 6

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

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

Нет необходимости в дальнейшей работе.

Ответ 7

Мой подход к этому - просто передать страницу в качестве параметра вспомогательному методу. Поэтому в вашем примере это будет:

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

Затем в вашем представлении Razor, где вам это нужно, назовите его следующим образом:

@YourHelperFilename.DoSomething(this)

Выполнение этого немедленно дает вам доступ к свойствам страницы, таким как Html или Url, которые вы обычно используете (и через это расширения HtmlHelper).

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

Ответ 8

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

MVC 3 RTM только что была обновлена, вы используете эту или бета-версию?