Uso de extensiones MVC HtmlHelper desde vistas declarativas de Razor

121

Intenté crear un asistente declarativo Razor en mi carpeta App_Code para un proyecto MVC 3 RTM.

El problema con el que me encontré fue que las extensiones MVC HtmlHelper, como ActionLink, no están disponibles. Esto se debe a que los ayudantes compilados se derivan System.Web.WebPages.HelperPage, y aunque exponen una Htmlpropiedad, es de tipo en System.Web.WebPages.HtmlHelperlugar de System.Web.Mvc.HtmlHelper.

Un ejemplo del tipo de error que estaba recibiendo es:

'System.Web.Mvc.HtmlHelper' no contiene una definición para 'ActionLink' y no se puede encontrar ningún método de extensión 'ActionLink' que acepte un primer argumento de tipo 'System.Web.Mvc.HtmlHelper' (falta una directiva de uso o una referencia de ensamblaje?)

Mi única solución ha sido crear mi propio HelperPage y anular la propiedad 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; }
    }
}

Luego tengo que escribir lo siguiente en la parte superior de cada ayudante:

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

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

¿Está destinado a ser tan difícil en MVC 3, o estoy haciendo algo mal?

Paul Stovell
fuente
44
Si necesita también el ayudante de Url, puede agregar esta línea de código a HelperPage: UrlHelper Url estática pública {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Respuestas:

42

Eche un vistazo a Marcindla respuesta a esta pregunta. Lo que está experimentando es una limitación de poner vistas declarativas en la App_Codecarpeta.

Poner sus ayudantes en App_Code funciona pero tiene ciertas limitaciones que afectan ciertos escenarios de MVC (por ejemplo: sin acceso a MVC Html. Helpers estándar)

Omar
fuente
1
Nota para otros lectores: esta respuesta es absolutamente correcta, pero también revise la contribución adicional de Andrew Nurse a continuación para una posible solución.
Jordan Gray
38

Creé un método de extensión para el ayudante de WebPages para poder acceder al ayudante de la página.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}
Jake Hoffner
fuente
44
Uso:@Html.GetPageHelper().ActionLink("actioname")
ciervo
Esto funciona para mí, pero tuve que agregar @using System.Web.Mvcy @using System.Web.Mvc.Htmlen el archivo de ayuda cshtml dentro de App_Code
Tomino
1
¿Por qué hay clases separadas de HtmlHelper? Debería ser igual ya sea en App_Code o en Views. El diseño épico medio implementado falla.
Triynko
Me refirieron aquí por weblogs.asp.net/scottgu/… que hace un buen trabajo al describir cómo crear ayudantes "globales" de Razor. Entonces, si solo necesita la HtmlHelperclase para fines de codificación, encontré una forma aún más rápida de hacerlo a través de la clase estática Microsoft.Security.Application.Encodercomo en:Encoder.HtmlAttributeEncode(value)
Matt Borja
11

Omar tiene la respuesta correcta aquí, pero quería agregar algo (no dude en marcar la respuesta de Omar como la respuesta).

Sabíamos esto en v1 y no pudimos obtener una solución excelente en el producto, pero David Ebbo (un arquitecto del equipo ASP.Net) publicó una muestra de un generador de código de Visual Studio que es básicamente una primera exploración de El tipo de ideas que estamos buscando para que esto funcione correctamente: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

¡Pruébalo y ve lo que piensas! Avísele a David si tiene comentarios publicando en su blog.

Andrew Stanton-Enfermera
fuente
2
¿Hay planes para solucionar esto en la próxima versión de Razor? Noté que esto sigue siendo un problema en VS 11 Beta.
Omar
9

Respuesta similar a @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")

Fuente: Dino Esposito - Programación de Microsoft ASP.NET MVC

Greg Gum
fuente
1
Es ridículo que esto sea incluso necesario, y que estos no son solo parte de la clase base para las vistas en App_Code.
Triynko
7

Una solución alternativa:

Agregue esto en la parte superior de su archivo razor-helper:

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

entonces llámalo así:

@HHtml.ActionLink("actionname")
Alex
fuente
Parecía que funcionó inicialmente para mí, pero cuando llamé al ayudante nuevamente obtuve 'el valor no cae dentro del rango esperado'.
d219
3

Mi enfoque para esto es simplemente pasar la página como parámetro al método auxiliar. Entonces, en su ejemplo, sería:

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

Luego, en su vista Razor donde lo necesita, llámelo así:

@YourHelperFilename.DoSomething(this)

Hacer esto inmediatamente te da acceso a propiedades de página como Htmlo Urlque usualmente tienes (y a través de eso las HtmlHelperextensiones).

Como beneficio adicional (si lo requiere), también obtiene acceso a propiedades de instancia, como las de la página ViewData.

Dejan
fuente
3

Para beneficio de los buscadores, obtuve el mismo error al crear vistas MVC como parte de una biblioteca de clases (para la reutilización de componentes). La solución, parcialmente aludida anteriormente, fue agregar lo siguiente usando declaraciones en la parte superior del archivo .cshtml:

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

No se necesita más trabajo.

HockeyJ
fuente
Mis ayudantes en mi .cshtml bajo App_Code no fueron reconocidos en Intellisense. Agregar @using System.Web.Mvc.Html en la parte superior de mi .cshtml en App_code funcionó.
Cuando hago esto, me pongo "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."al flotar @using System.Web.Mvc. ¿Algunas ideas?
JoeBrockhaus
Eso no hace ninguna diferencia para mí
mems
0

Sé que hay algunos problemas de inteligencia con MVC 3. Creo que los ayudantes seguirán funcionando si tiene el espacio de nombres configurado en web.config.

MVC 3 RTM acaba de ser lanzado ¿Estás usando esto o una versión beta?

Lee Smith
fuente
0

Parece que ASP.NET MVC ha solucionado este problema en VS 2013. Vea esta publicación http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht

Omar
fuente
No para nada. Intellisense no está recogiendo métodos de extensión, y tengo VS2013 actualización 5. Tengo @using System.Web.Mvc.Htmlen la parte superior del archivo cshtml en App_Code, pero escribir @Html ... no revela ninguno de los métodos de extensión como EditorFor. Es ridículo que esto no funcione después de 2 lanzamientos importantes y publicaciones de blog que afirman que se implementó. No es. De hecho, los métodos de extensión no pueden funcionar, porque están dirigidos a la clase System.Web.Mvc.HtmlHelper, no a la clase System.Web.WebPages.HtmlHelper, que está expuesta por la clase System.Web.WebPages.HelperPage.
Triynko