Verwenden von MVC HtmlHelper-Erweiterungen aus deklarativen Razor-Ansichten

121

Ich habe versucht, einen deklarativen Razor-Helfer in meinem App_Code-Ordner für ein MVC 3 RTM-Projekt zu erstellen.

Das Problem, auf das ich gestoßen bin, war, dass die MVC HtmlHelper-Erweiterungen wie ActionLink nicht verfügbar sind. Dies liegt daran, dass die kompilierten Helfer von System.Web.WebPages.HelperPageeiner HtmlEigenschaft abgeleitet sind und diese verfügbar machen, obwohl sie System.Web.WebPages.HtmlHelpereher vom Typ als vom Typ ist System.Web.Mvc.HtmlHelper.

Ein Beispiel für die Art von Fehler, die ich bekam, ist:

'System.Web.Mvc.HtmlHelper' enthält keine Definition für 'ActionLink' und es konnte keine Erweiterungsmethode 'ActionLink' gefunden werden, die ein erstes Argument vom Typ 'System.Web.Mvc.HtmlHelper' akzeptiert (fehlt Ihnen eine using-Direktive) oder eine Montagereferenz?)

Meine einzige Lösung bestand darin, meine eigene HelperPage zu erstellen und die HTML-Eigenschaft zu überschreiben:

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; }
    }
}

Ich muss dann oben auf jeden Helfer folgendes schreiben:

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

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

Soll es in MVC 3 so schwer sein, oder mache ich etwas falsch?

Paul Stovell
quelle
4
Wenn Sie auch den Url-Helfer benötigen, können Sie diese Codezeile zu HelperPage hinzufügen: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Antworten:

42

Schauen Sie sich Marcinddie Antwort auf diese Frage an. Was Sie erleben, ist eine Einschränkung beim Einfügen deklarativer Ansichten in den App_CodeOrdner.

Das Einfügen Ihrer Helfer in App_Code funktioniert, weist jedoch bestimmte Einschränkungen auf, die sich auf bestimmte MVC-Szenarien auswirken (z. B. kein Zugriff auf Standard-MVC-HTML-Helfer).

Omar
quelle
1
Hinweis für andere Leser: Diese Antwort ist absolut richtig, aber lesen Sie auch den zusätzlichen Beitrag von Andrew Nurse unten, um eine mögliche Problemumgehung zu finden.
Jordan Gray
38

Ich habe eine Erweiterungsmethode für den WebPages-Helfer erstellt, damit ich auf den Seiten-Helfer zugreifen kann.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}
Jake Hoffner
quelle
4
Verwendung:@Html.GetPageHelper().ActionLink("actioname")
Deerchao
Dies funktioniert für mich, aber ich hatte hinzufügen @using System.Web.Mvcund @using System.Web.Mvc.Htmlin cshtml Helfer Datei in App_Code
Tomino
1
Warum gibt es separate HtmlHelper-Klassen? Es sollte gleich sein, ob es sich um App_Code oder Views handelt. Episches halbimplementiertes Design schlägt fehl.
Triynko
Wurde hier von weblogs.asp.net/scottgu/… verwiesen, das einen guten Job darin macht, zu beschreiben, wie man "globale" Razor-Helfer erstellt. Wenn Sie die HtmlHelperKlasse also nur für Codierungszwecke benötigen , habe ich einen noch schnelleren Weg gefunden, dies über die statische Klasse zu tun, Microsoft.Security.Application.Encoderwie in:Encoder.HtmlAttributeEncode(value)
Matt Borja
11

Omar hat hier die richtige Antwort, aber ich wollte etwas hinzufügen (zögern Sie nicht, Omars Antwort als Antwort zu markieren).

Wir waren uns dessen in Version 1 bewusst und konnten keine großartige Lösung für das Produkt finden, aber David Ebbo (ein Architekt im ASP.Net-Team) hat ein Beispiel eines Visual Studio-Codegenerators veröffentlicht, bei dem es sich im Grunde um eine erste Untersuchung handelt Die Art von Ideen, die wir suchen, damit dies richtig funktioniert: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Probieren Sie das aus und sehen Sie, was Sie denken! Lassen Sie David wissen, wenn Sie Kommentare haben, indem Sie in seinem Blog posten.

Andrew Stanton-Krankenschwester
quelle
2
Gibt es Pläne, dies in der nächsten Version von Razor zu beheben? Ich habe festgestellt, dass dies in VS 11 Beta immer noch ein Problem ist.
Omar
9

Ähnlich wie bei @Jakes Antwort:

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; }
    }

}

Verwendung:

@MvcIntrinsics.Html.Raw("test")

Quelle: Dino Esposito - Programmieren von Microsoft ASP.NET MVC

Greg Gum
quelle
1
Es ist lächerlich, dass dies sogar notwendig ist und dass diese nicht nur Teil der Basisklasse für Ansichten in App_Code sind.
Triynko
7

Eine alternative Lösung:

Fügen Sie dies oben in Ihre Rasiermesser-Hilfedatei ein:

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

dann nenne es so:

@HHtml.ActionLink("actionname")
Alex
quelle
Das sah anfangs so aus, als hätte es bei mir funktioniert, aber als ich den Helfer erneut anrief, bekam ich "Wert fällt nicht in den erwarteten Bereich".
d219
3

Mein Ansatz besteht darin, die Seite einfach als Parameter an die Hilfsmethode zu übergeben. In Ihrem Beispiel wäre es also:

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

Dann nennen Sie es in Ihrer Razor-Ansicht, wo Sie es brauchen, so:

@YourHelperFilename.DoSomething(this)

Wenn Sie dies sofort tun, erhalten Sie Zugriff auf Seiteneigenschaften wie Htmloder Urldie Sie normalerweise haben (und dadurch auf die HtmlHelperErweiterungen).

Als zusätzlichen Vorteil (falls erforderlich) erhalten Sie auch Zugriff auf Instanzeigenschaften wie die der Seite ViewData.

Dejan
quelle
3

Für Suchende wurde beim Erstellen von MVC-Ansichten als Teil einer Klassenbibliothek (zur Wiederverwendung von Komponenten) derselbe Fehler angezeigt. Die Lösung, auf die oben teilweise hingewiesen wurde, bestand darin, die folgenden using-Anweisungen oben in der CSHTM-Datei hinzuzufügen:

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

Keine weiteren Arbeiten notwendig.

HockeyJ
quelle
Meine Helfer in meiner .cshtml unter App_Code wurden in Intellisense nicht erkannt. Das Hinzufügen von @using System.Web.Mvc.Html oben in meiner .cshtml unter App_code hat funktioniert.
Wenn ich das mache, bekomme ich "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."beim Schweben @using System.Web.Mvc. Irgendwelche Ideen?
JoeBrockhaus
Das macht für mich keinen Unterschied
Mems
0

Ich weiß, dass es bei MVC 3 einige Intellisense-Probleme gibt. Ich denke, die Helfer funktionieren weiterhin, wenn Sie den Namespace in web.config festgelegt haben.

MVC 3 RTM wurde gerade veröffentlicht. Verwenden Sie diese oder eine Beta?

Lee Smith
quelle
0

Es sieht so aus, als hätte ASP.NET MVC dieses Problem in VS 2013 behoben. Siehe diesen Beitrag http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht

Omar
quelle
Nein, überhaupt nicht. Intellisense greift nicht auf Erweiterungsmethoden auf, und ich habe VS2013-Update 5. Ich habe @using System.Web.Mvc.Htmloben in der cshtml-Datei in App_Code, aber das Schreiben von @Html .... zeigt keine der Erweiterungsmethoden wie z EditorFor. Es ist lächerlich, dass dies nach 2 Hauptversionen und Blog-Posts, die behaupten, dass es implementiert wurde, nicht funktioniert. Es ist nicht. Tatsächlich können die Erweiterungsmethoden nicht funktionieren, da sie auf die System.Web.Mvc.HtmlHelper-Klasse abzielen, nicht auf die System.Web.WebPages.HtmlHelper-Klasse, die von der System.Web.WebPages.HelperPage-Klasse verfügbar gemacht wird.
Triynko