Utilisation des extensions MVC HtmlHelper à partir de vues déclaratives Razor

121

J'essayais de créer un assistant déclaratif Razor dans mon dossier App_Code pour un projet MVC 3 RTM.

Le problème que j'ai rencontré était que les extensions MVC HtmlHelper, comme ActionLink, ne sont pas disponibles. C'est parce que les helpers compilés dérivent de System.Web.WebPages.HelperPage, et bien qu'il expose une Htmlpropriété, son de type System.Web.WebPages.HtmlHelperplutôt que System.Web.Mvc.HtmlHelper.

Un exemple du type d'erreur que j'obtenais est:

'System.Web.Mvc.HtmlHelper' ne contient pas de définition pour 'ActionLink' et aucune méthode d'extension 'ActionLink' acceptant un premier argument de type 'System.Web.Mvc.HtmlHelper' n'a pu être trouvée (il vous manque une directive using ou une référence d'assemblage?)

Ma seule solution a été de créer ma propre HelperPage et de remplacer la propriété 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; }
    }
}

Je dois ensuite écrire ce qui suit en haut de chaque aide:

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

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

Est-ce censé être aussi difficile dans MVC 3, ou est-ce que je fais quelque chose de mal?

Paul Stovell
la source
4
Si vous avez également besoin de l'aide Url, ajoutez cette ligne de code à HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Réponses:

42

Jetez un œil à Marcindla réponse à cette question. Ce que vous rencontrez est une limitation de la mise des vues déclaratives dans le App_Codedossier.

Mettre vos helpers dans App_Code fonctionne mais présente certaines limitations qui affectent certains scénarios MVC (par exemple: pas d'accès aux helpers MVC Html standard)

Omar
la source
1
Note aux autres lecteurs: cette réponse est absolument correcte, mais consultez également la contribution supplémentaire d'Andrew Nurse ci-dessous pour une solution de contournement potentielle.
Jordan Grey
38

J'ai créé une méthode d'extension pour l'assistant WebPages afin que je puisse accéder à l'assistant de page.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}
Jake Hoffner
la source
4
Utilisation:@Html.GetPageHelper().ActionLink("actioname")
deerchao
Cela fonctionne pour moi, mais j'ai dû ajouter @using System.Web.Mvcet @using System.Web.Mvc.Htmldans le fichier helpers cshtml dans App_Code
Tomino
1
Pourquoi existe-t-il une classe HtmlHelper distincte? Ce devrait être la même chose que ce soit dans App_Code ou Views. La conception épique à moitié implémentée échoue.
Triynko du
Vous avez été référé ici par weblogs.asp.net/scottgu/ ... qui fait un bon travail en décrivant comment créer des helpers Razor "globaux". Donc, si vous n'avez besoin de la HtmlHelperclasse qu'à des fins d'encodage, j'ai trouvé un moyen encore plus rapide de le faire via la classe statique Microsoft.Security.Application.Encodercomme dans:Encoder.HtmlAttributeEncode(value)
Matt Borja
11

Omar a la bonne réponse ici, mais je voulais ajouter quelque chose (n'hésitez pas à marquer la réponse d'Omar comme la réponse).

Nous étions conscients de cela dans la v1 et n'avons pas été en mesure d'obtenir une excellente solution dans le produit, mais David Ebbo (un architecte de l'équipe ASP.Net) a publié un exemple de Visual Studio Code Generator qui est essentiellement une première exploration de le type d'idées que nous recherchons pour que cela fonctionne correctement: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Essayez cela et voyez ce que vous en pensez! Faites savoir à David si vous avez des commentaires en publiant sur son blog.

Andrew Stanton-infirmière
la source
2
Est-il prévu de résoudre ce problème dans la prochaine version de Razor? J'ai remarqué que c'était toujours un problème dans VS 11 Beta.
Omar
9

Similaire à la réponse @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; }
    }

}

Usage:

@MvcIntrinsics.Html.Raw("test")

Source: Dino Esposito - Programmation Microsoft ASP.NET MVC

Greg Gum
la source
1
Il est ridicule que cela soit même nécessaire et que ceux-ci ne font pas simplement partie de la classe de base pour les vues dans App_Code.
Triynko du
7

Une solution alternative:

Ajoutez ceci au-dessus de votre fichier razor-helper:

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

alors appelez-le comme ceci:

@HHtml.ActionLink("actionname")
Alex
la source
Cela semblait avoir fonctionné au départ pour moi, mais en appelant à nouveau l'assistant, j'ai obtenu `` la valeur ne tombe pas dans la plage attendue ''.
d219
3

Mon approche consiste simplement à transmettre la page en tant que paramètre à la méthode d'assistance. Donc, dans votre exemple, ce serait:

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

Ensuite, dans votre vue Razor où vous en avez besoin, appelez-le comme ceci:

@YourHelperFilename.DoSomething(this)

Cela vous donne immédiatement accès aux propriétés de la page comme Htmlou Urlque vous avez habituellement (et à travers cela les HtmlHelperextensions).

Comme avantage supplémentaire (si vous en avez besoin), vous avez également accès aux propriétés d'instance telles que la page ViewData.

Dejan
la source
3

Pour le bénéfice des chercheurs, j'ai eu la même erreur lors de la création de vues MVC dans le cadre d'une bibliothèque de classes (pour la réutilisation des composants). La solution, partiellement évoquée ci-dessus, consistait à ajouter les instructions using suivantes en haut du fichier .cshtml:

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

Aucun autre travail nécessaire.

HockeyJ
la source
Mes assistants dans mon .cshtml sous App_Code n'étaient pas reconnus dans Intellisense. L'ajout de @using System.Web.Mvc.Html en haut de mon .cshtml sous App_code a fonctionné.
Quand je fais cela, je reçois "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."en planant @using System.Web.Mvc. Des idées?
JoeBrockhaus le
Cela ne fait aucune différence pour moi
mems
0

Je sais qu'il y a des problèmes d'intellisense avec MVC 3. Je pense que les helpers fonctionneront toujours si vous avez défini l'espace de noms dans web.config.

MVC 3 RTM vient de sortir, utilisez-vous ceci ou une version bêta?

Lee Smith
la source
0

On dirait que ASP.NET MVC a résolu ce problème dans VS 2013. Voir cet article http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht

Omar
la source
Non pas du tout. Intellisense ne prend pas en charge les méthodes d'extension, et j'ai la mise à jour VS2013 5. J'ai @using System.Web.Mvc.Htmlen haut du fichier cshtml dans App_Code, mais écrire @Html .... ne révèle aucune des méthodes d'extension telles que EditorFor. Il est ridicule que cela ne fonctionne pas après 2 versions majeures et des articles de blog affirmant qu'il a été implémenté. Ce n'est pas. En fait, les méthodes d'extension ne peuvent pas fonctionner, car elles ciblent la classe System.Web.Mvc.HtmlHelper, et non la classe System.Web.WebPages.HtmlHelper, qui est exposée par la classe System.Web.WebPages.HelperPage.
Triynko