Using MVC HtmlHelper extensions from Razor declarative views

I was trying to create a Razor declarative helper in my App_Code folder for an MVC 3 RTM project.

The problem I ran into was that the MVC HtmlHelper extensions, like ActionLink, aren't available. This is because the compiled helpers derive from System.Web.WebPages.HelperPage, and though it exposes an Html property, its of type System.Web.WebPages.HtmlHelper rather than System.Web.Mvc.HtmlHelper.

An example of the kind of error I was getting is:

'System.Web.Mvc.HtmlHelper' does not contain a definition for 'ActionLink' and no extension method 'ActionLink' accepting a first argument of type 'System.Web.Mvc.HtmlHelper' could be found (are you missing a using directive or an assembly reference?)

My only solution has been to create my own HelperPage and override the Html property:

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; }
}
}

I then have to write the following at the top of every helper:

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


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

Is it meant to be this hard in MVC 3, or am I doing something wrong?

71430 次浏览

我知道 MVC 3存在一些智能感知问题。我认为如果在 web.config 中设置了名称空间,那么助手仍然可以工作。

MVC3RTM 刚刚发布,你是使用这个还是测试版?

看看 Marcind的回答对这个问题的回答。您正在经历的是将声明性视图放入 App_Code文件夹的限制。

Putting your helpers in App_Code works 但有一定的局限性 影响某些 MVC 场景(为 例如: 无法访问标准 MVC Html.helpers)

奥马尔的回答是正确的,但我想补充一些东西(请随意将奥马尔的回答标记为答案)。

我们在 v1中意识到了这一点,但是没能在产品中得到很好的修复,但是 David Ebbo (ASP.Net 团队的架构师)发布了一个 Visual Studio 代码生成器的样本,这个样本基本上是对我们正在寻找的使其正常工作的想法的第一次探索: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries.aspx

Try that out and see what you think! Let David know if you have comments by posting on his blog.

I created an extension method for the WebPages helper so that I can get access to the page helper.

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

为了搜索者的利益,我在创建作为类库一部分的 MVC 视图(用于组件重用)时也得到了同样的错误。上面部分提到的解决方案是在。Cshtml 文件:

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

没有进一步的工作必要。

类似于@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

看起来 ASP.NET MVC 在 VS 2013中已经解决了这个问题

另一种解决办法:

在你的剃须刀助手文件上添加以下内容:

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

那就这么说吧:

@HHtml.ActionLink("actionname")

我的方法是简单地将页面作为参数传递给 helper 方法。所以在你的例子中是这样的:

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

然后在你的 Razor 视图中,你需要它的地方是这样的:

@YourHelperFilename.DoSomething(this)

立即执行此操作将使您能够访问通常具有的页面属性,如 HtmlUrl(并通过它访问 HtmlHelper扩展)。

作为一个额外的好处(如果需要的话) ,您还可以访问实例属性,例如页面的 ViewData