Usando le estensioni MVC HtmlHelper dalle viste dichiarative di Razor

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

Il problema che ho riscontrato è che le estensioni MVC HtmlHelper, come ActionLink, non sono disponibili. Questo perché gli helper compilati derivano da System.Web.WebPages.HelperPage e sebbene esponga una proprietà Html , è di tipo System.Web.WebPages.HtmlHelper piuttosto che System.Web.Mvc.HtmlHelper .

Un esempio del tipo di errore che stavo ottenendo è:

‘System.Web.Mvc.HtmlHelper’ non contiene una definizione per ‘ActionLink’ e non è ansible trovare alcun metodo di estensione ‘ActionLink’ che accetta un primo argomento di tipo ‘System.Web.Mvc.HtmlHelper’ (manca una direttiva using o un riferimento all’assembly?)

La mia unica soluzione è stata creare il mio 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 aiuto:

 @inherits FunnelWeb.Web.App_Code.HelperPage @using System.Web.Mvc @using System.Web.Mvc.Html @helper DoSomething() { @Html.ActionLink("Index", "Home") } 

È pensato per essere così difficile in MVC 3 o sto facendo qualcosa di sbagliato?

Dai un’occhiata alla risposta di Marcind a questa domanda. Quello che stai vivendo è una limitazione di mettere le viste dichiarative nella cartella App_Code .

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

Ho creato un metodo di estensione per l’helper di WebPages in modo che possa ottenere l’accesso all’helper di pagina.

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

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

Ne eravamo consapevoli 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 osservando per farlo funzionare correttamente: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries aspx

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

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 – Programmazione di Microsoft ASP.NET MVC

Una soluzione alternativa:

Aggiungi questo sopra il file del tuo razor-helper:

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

quindi chiamalo così:

 @HHtml.ActionLink("actionname") 

Per il vantaggio degli utenti, ho ottenuto lo stesso errore durante la creazione di viste MVC come parte di una libreria di classi (per il riutilizzo dei componenti). La soluzione, in parte citata sopra, è stata quella di aggiungere le seguenti istruzioni using nella parte superiore del file .cshtml:

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

Non è necessario ulteriore lavoro.

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

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

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

 @YourHelperFilename.DoSomething(this) 

In questo modo puoi accedere immediatamente alle proprietà della pagina come Html o Url che solitamente hai (e attraverso le estensioni HtmlHelper ).

Come ulteriore vantaggio (se richiesto), si ottiene anche l’accesso a proprietà di istanza come ViewData della pagina.

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

MVC 3 RTM è appena stato rilasciato se stai usando questa o una beta?

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-questo- HtmlHelper-HT