Utilizzo delle estensioni HtmlHelper MVC dalle visualizzazioni dichiarative Razor


121

Stavo cercando di creare un helper dichiarativo Razor nella mia cartella App_Code per un progetto MVC 3 RTM.

Il problema che ho riscontrato è stato che le estensioni MVC HtmlHelper, come ActionLink, non sono disponibili. Questo perché gli helper compilati derivano da System.Web.WebPages.HelperPagee sebbene esponga una Htmlproprietà, è di tipo System.Web.WebPages.HtmlHelperpiuttosto che System.Web.Mvc.HtmlHelper.

Un esempio del tipo di errore che stavo ricevendo è:

"System.Web.Mvc.HtmlHelper" non contiene una definizione per "ActionLink" e nessun metodo di estensione "ActionLink" che accetta un primo argomento di tipo "System.Web.Mvc.HtmlHelper" potrebbe essere trovato (manca una direttiva using o un riferimento all'assembly?)

La mia unica soluzione è stata creare la mia HelperPage e sovrascrivere la proprietà 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; }
    }
}

Devo quindi scrivere quanto segue all'inizio di ogni helper:

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

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

Dovrebbe essere così difficile in MVC 3 o sto facendo qualcosa di sbagliato?


4
Se hai bisogno anche dell'helper Url puoi aggiungere questa riga di codice a HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Risposte:


42

Dai un'occhiata alla Marcindrisposta di questa domanda. Quello che stai riscontrando è una limitazione dell'inserimento di viste dichiarative nella App_Codecartella.

Mettere i tuoi helper in App_Code funziona ma presenta alcune limitazioni che influiscono su determinati scenari MVC (ad esempio: nessun accesso agli helper Html MVC standard)


1
Nota per altri lettori: questa risposta è assolutamente corretta, ma controlla anche il contributo aggiuntivo di Andrew Nurse di seguito per una potenziale soluzione alternativa.
Jordan Grey

38

Ho creato un metodo di estensione per l'helper delle pagine Web in modo da poter accedere all'helper della pagina.

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

4
Utilizzo:@Html.GetPageHelper().ActionLink("actioname")
deerchao

Questo funziona per me, ma ho dovuto aggiungere @using System.Web.Mvce @using System.Web.Mvc.Htmlnel file degli helper cshtml all'interno di App_Code
Tomino

1
Perché sono presenti classi HtmlHelper separate? Dovrebbe essere lo stesso sia in App_Code che in Views. Il design epico implementato a metà fallisce.
Triynko

Sono stato segnalato qui da weblogs.asp.net/scottgu/… che fa un buon lavoro nel descrivere come creare helper Razor "globali". Quindi, se hai bisogno della HtmlHelperclasse solo per scopi di codifica, ho trovato un modo ancora più rapido per farlo tramite la classe statica Microsoft.Security.Application.Encodercome in:Encoder.HtmlAttributeEncode(value)
Matt Borja

11

Omar ha la risposta giusta qui, ma volevo aggiungere qualcosa (sentiti libero di contrassegnare la risposta di Omar come risposta).

Eravamo consapevoli di questo nella v1 e non siamo stati in grado di ottenere una grande correzione nel prodotto, ma David Ebbo (un architetto del team ASP.Net) ha pubblicato un esempio di un generatore di codice di Visual Studio che è fondamentalmente una prima esplorazione di il tipo di idee che stiamo cercando di far funzionare correttamente: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries aspx

Provalo e vedi cosa ne pensi! Fai sapere a David se hai commenti pubblicandoli sul suo blog.


2
Ci sono piani per risolvere questo problema nella prossima versione di Razor? Ho notato che questo è ancora un problema in VS 11 Beta.
Omar

9

Simile alla risposta di @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 - Programming Microsoft ASP.NET MVC


1
È ridicolo che ciò sia persino necessario e che questi non facciano solo parte della classe base per le visualizzazioni in App_Code.
Triynko

7

Una soluzione alternativa:

Aggiungi questo sopra il tuo file razor-helper:

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

quindi chiamalo così:

@HHtml.ActionLink("actionname")

All'inizio sembrava che funzionasse per me, ma quando ho chiamato di nuovo l'assistente ho ottenuto "il valore non rientra nell'intervallo previsto".
d219

3

Il mio approccio a questo è semplicemente passare la pagina come parametro al metodo di supporto. Quindi nel tuo esempio sarebbe:

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

Quindi nella tua vista Razor dove ti serve chiamalo in questo modo:

@YourHelperFilename.DoSomething(this)

In questo modo puoi accedere immediatamente alle proprietà della pagina come Htmlo Urlche di solito hai (e tramite le HtmlHelperestensioni).

Come ulteriore vantaggio (se necessario), puoi anche accedere alle proprietà dell'istanza come quelle della pagina ViewData.


3

A vantaggio dei ricercatori, ho ricevuto lo stesso errore durante la creazione di viste MVC come parte di una libreria di classi (per il riutilizzo dei componenti). La soluzione, parzialmente accennata sopra, è stata quella di aggiungere le seguenti istruzioni using all'inizio del file .cshtml:

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

Nessun ulteriore lavoro necessario.


I miei helper nel mio .cshtml in App_Code non sono stati riconosciuti in Intellisense. L'aggiunta di @using System.Web.Mvc.Html nella parte superiore del mio .cshtml sotto App_code ha funzionato.

Quando lo faccio, ottengo "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."quando in bilico @using System.Web.Mvc. Qualche idea?
JoeBrockhaus

Questo non fa differenza per me
mems

0

So che ci sono alcuni problemi intellisense con MVC 3. Penso che gli helper funzioneranno ancora se lo spazio dei nomi è impostato in web.config.

MVC 3 RTM è appena stato rilasciato, stai usando questo o una beta?


0

Sembra che ASP.NET MVC abbia risolto questo problema in VS 2013. Vedi questo post http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- HtmlHelper-HT


No, per niente. Intellisense non sta rilevando i metodi di estensione e ho l'aggiornamento VS2013 5. Ho @using System.Web.Mvc.Htmlall'inizio del file cshtml in App_Code, ma scrivendo @Html .... non viene rivelato nessuno dei metodi di estensione come EditorFor. È ridicolo che questo non funzioni dopo 2 versioni principali e post di blog che affermano che è stato implementato. Non è. In effetti, i metodi di estensione non possono funzionare, perché hanno come destinazione la classe System.Web.Mvc.HtmlHelper, non la classe System.Web.WebPages.HtmlHelper, che è esposta dalla classe System.Web.WebPages.HelperPage.
Triynko
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.