Usando extensões MVC HtmlHelper a partir de visualizações declarativas do Razor

121

Eu estava tentando criar um auxiliar declarativo Razor na minha pasta App_Code para um projeto MVC 3 RTM.

O problema que encontrei foi que as extensões MVC HtmlHelper, como o ActionLink, não estão disponíveis. Isso ocorre porque os auxiliares compilados derivam System.Web.WebPages.HelperPagee, embora exponha uma Htmlpropriedade, é do tipo System.Web.WebPages.HtmlHelpere não System.Web.Mvc.HtmlHelper.

Um exemplo do tipo de erro que eu estava recebendo é:

'System.Web.Mvc.HtmlHelper' não contém uma definição para 'ActionLink' e nenhum método de extensão 'ActionLink' que aceita um primeiro argumento do tipo 'System.Web.Mvc.HtmlHelper' pode ser encontrado (você está perdendo uma diretiva de uso ou uma referência de montagem?)

Minha única solução foi criar meu próprio HelperPage e substituir a propriedade 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; }
    }
}

Eu tenho que escrever o seguinte no topo de todo ajudante:

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

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

É para ser tão difícil no MVC 3, ou estou fazendo algo errado?

Paul Stovell
fonte
4
Se você também precisar do ajudante de URL, adicione esta linha de código ao HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli 24/10

Respostas:

42

Veja a Marcindresposta desta pergunta. O que você está enfrentando é uma limitação de colocar visualizações declarativas na App_Codepasta.

A colocação de seus auxiliares no App_Code funciona, mas possui certas limitações que afetam determinados cenários do MVC (por exemplo: nenhum acesso ao MVC padrão. Helpers)

Omar
fonte
1
Nota para outros leitores: esta resposta é absolutamente correta, mas verifique também a contribuição adicional de Andrew Nurse para uma possível solução alternativa.
Jordan Gray
38

Criei um método de extensão para o auxiliar de páginas da Web, para que eu possa acessar o auxiliar de página.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}
Jake Hoffner
fonte
4
Uso:@Html.GetPageHelper().ActionLink("actioname")
deerchao
Isso funciona para mim, mas eu tinha para adicionar @using System.Web.Mvce @using System.Web.Mvc.Htmlem arquivo de ajudantes cshtml dentro App_Code
Tomino
1
Por que existem classes HtmlHelper separadas? Deve ser o mesmo, seja no App_Code ou no Views. O projeto épico semi-implementado falha.
Triynko 26/07/2015
Foi referido aqui por weblogs.asp.net/scottgu/…, que faz um bom trabalho descrevendo como criar ajudantes "globais" do Razor. Portanto, se você só precisa da HtmlHelperclasse para fins de codificação, eu encontrei uma maneira ainda mais rápida de fazer isso é através da classe estática Microsoft.Security.Application.Encodercomo em:Encoder.HtmlAttributeEncode(value)
Matt Borja
11

Omar tem a resposta certa aqui, mas eu queria acrescentar algo (sinta-se à vontade para marcar a resposta de Omar como a resposta).

Estávamos cientes disso na v1 e não conseguimos uma ótima correção no produto, mas David Ebbo (um arquiteto da equipe do ASP.Net) publicou uma amostra de um gerador de código do Visual Studio que é basicamente a primeira exploração de o tipo de idéias que estamos buscando para fazer isso funcionar corretamente: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Experimente e veja o que você pensa! Deixe David saber se você tem comentários postando em seu blog.

Andrew Stanton-Nurse
fonte
2
Existem planos para corrigir isso na próxima versão do Razor? Percebi que isso ainda é um problema no VS 11 Beta.
Omar
9

Semelhante à resposta @ 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; }
    }

}

Uso:

@MvcIntrinsics.Html.Raw("test")

Fonte: Dino Esposito - Programação Microsoft ASP.NET MVC

Greg Gum
fonte
1
É ridículo que isso seja necessário e que eles não sejam apenas parte da classe base para visualizações no App_Code.
Triynko 26/07/2015
7

Uma solução alternativa:

Adicione isso em cima do seu arquivo de barbeador:

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

então chame assim:

@HHtml.ActionLink("actionname")
Alex
fonte
Parecia que funcionou inicialmente para mim, mas ao chamar o ajudante novamente, obtive 'valor não cai dentro do intervalo esperado'.
D219 6/08
3

Minha abordagem para isso é simplesmente passar a página como um parâmetro para o método auxiliar. Então, no seu exemplo, seria:

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

Em sua visão do Razor, onde você precisa, chame assim:

@YourHelperFilename.DoSomething(this)

Fazer isso imediatamente dá acesso a propriedades da página como Htmlou Urlque você normalmente possui (e por meio disso as HtmlHelperextensões).

Como um benefício adicional (se você precisar disso), você também terá acesso a propriedades da instância, como as da página ViewData.

Dejan
fonte
3

Para o benefício dos pesquisadores, recebi o mesmo erro ao criar visualizações MVC como parte de uma biblioteca de classes (para reutilização de componentes). A solução, parcialmente mencionada acima, foi adicionar as seguintes instruções usando na parte superior do arquivo .cshtml:

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

Nenhum trabalho adicional é necessário.

HockeyJ
fonte
Meus auxiliares no meu arquivo .cshtml em App_Code não foram reconhecidos no Intellisense. Adicionar @ usando System.Web.Mvc.Html na parte superior do meu .cshtml em App_code funcionou.
Quando faço isso, fico "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."pairando @using System.Web.Mvc. Alguma ideia?
JoeBrockhaus
Isso não faz diferença para mim
MEMS
0

Sei que há alguns problemas de inteligência com o MVC 3. Acho que os ajudantes ainda funcionarão se você tiver o espaço para nome definido no web.config.

O MVC 3 RTM acaba de ser lançado. Você está usando este ou um beta?

Lee Smith
fonte
0

Parece que o ASP.NET MVC corrigiu esse problema no VS 2013. Consulte esta postagem http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht

Omar
fonte
Não, de jeito nenhum. O Intellisense não está escolhendo métodos de extensão e eu tenho a atualização 5. do VS2013. Eu tenho @using System.Web.Mvc.Htmla parte superior do arquivo cshtml no App_Code, mas escrever @Html .... não revela nenhum dos métodos de extensão, como EditorFor. É ridículo que isso não funcione após 2 lançamentos importantes e postagens no blog que alegam que foi implementado. Não é. De fato, os métodos de extensão não podem funcionar, porque têm como alvo a classe System.Web.Mvc.HtmlHelper, não a classe System.Web.WebPages.HtmlHelper, que é exposta pela classe System.Web.WebPages.HelperPage.
Triynko 26/07/2015