Einführung in Custom Tag Helpers in ASP.NET MVC

Moderne Webanwendungen erfordern sauberen, wartbaren und wiederverwendbaren Ansichtscode. ASP.NET Core MVC bietet Tag-Helfer als leistungsstarken serverseitigen Mechanismus zur Transformation und Generierung von HTML-Markup direkt in Razor-Ansichten. Während das Framework mit einem reichen Satz von eingebauten Tag-Helfern für Formulare, Validierung, Caching und umgebungsspezifisches Rendering ausgestattet ist, erfordern reale Projekte oft maßgeschneiderte Komponenten, die domänenspezifische Logik- und Präsentationsmuster einkapseln.

Durch das Verschieben komplexer HTML-Generierung und bedingter Logik in wiederverwendbare Tag-Helfer-Klassen trennen Sie Präsentationsbedenken von View-Markup, verbessern die Testbarkeit und reduzieren die Duplizierung über große Codebasen hinweg. Dieser Artikel bietet eine umfassende Anleitung zum Erstellen benutzerdefinierter Tag-Helfer in ASP.NET Core MVC, die alles von der grundlegenden Klassenstruktur und Attributbindung bis hin zu fortgeschrittenen Szenarien wie Abhängigkeitsinjektion, asynchrone Verarbeitung und Tag-Helfer-Komponenten abdeckt. Jeder Abschnitt enthält praktische Beispiele und Best Practices, die Ihnen helfen, diese Technik in Ihren täglichen Entwicklungsworkflow zu integrieren.

Tag-Helfer in ASP.NET Core verstehen

Tag-Helfer sind serverseitige Komponenten, die am Rendern von HTML-Elementen in Razor-Ansichten beteiligt sind. Sie ermöglichen es Ihnen, C#-Code an bestimmte HTML-Elemente oder benutzerdefinierte Elementnamen anzuhängen und das Markup zu transformieren, bevor es an den Client gesendet wird. Im Gegensatz zu HTML-Helfern (die Methodenaufrufe wie verwenden), arbeiten Tag-Helfer mit dem Abgleich mit der vorhandenen HTML-Syntax, wodurch sich Ansichten für Designer und Frontend-Entwickler natürlicher anfühlen.

Beispielsweise führt der integrierte -Tag-Helfer Controller- und Aktionsattribute in die richtige URL ein. Tag-Helfer können Attribute ändern, das gesamte Element ersetzen, CSS-Klassen hinzufügen oder entfernen und sogar zusätzliches HTML einfügen. Sie laufen während der Razor View Execution Pipeline und haben vollen Zugriff auf den aktuellen Anforderungskontext, Modelldaten und registrierte Dienste.

Server-Side-Ausführungsmodell

Wenn eine Razor-Ansicht kompiliert wird, werden Tag-Helfer durch Assemblys und -Direktiven entdeckt. Das Framework wertet jedes HTML-Element mit allen registrierten Tag-Helfern aus und ruft ihre - oder -Methoden auf, wenn eine Übereinstimmung gefunden wird. Dies geschieht, bevor die endgültige HTML-Ausgabe generiert wird, so dass Tag-Helfer Elemente dynamisch anreichern oder ersetzen können.

Hauptunterschiede zu anderen View Composition Tools

  • HTML-Helfer: Erfordern C#-Methodenaufrufe innerhalb von Razor-Blöcken (), die den HTML-zentrischen Fluss unterbrechen können. Tag-Helfer integrieren sich direkt in die HTML-Syntax.
  • Partials: Gut für die Wiederverwendung statischer Markup-Blöcke, aber es fehlt die Fähigkeit, die Struktur basierend auf serverseitiger Logik ohne zusätzliche Ansichtsmodelle programmgesteuert zu ändern.
  • View Components: Ideal für komplexe, datengesteuerte Widgets mit eigener Logik und Rendering, aber sie erfordern eine separate Klassen- und Aufrufsyntax (). Tag-Helfer sind einfacher für elementorientierte Transformationen.

Warum sollten Sie Custom Tag Helpers erstellen?

Während integrierte Tag-Helfer viele gängige Szenarien abdecken, bieten benutzerdefinierte Tag-Helfer einzigartige Vorteile, die die Codequalität und die Produktivität der Entwickler direkt verbessern.

  • Encapsulate Complex Markup Patterns – Wiederholtes Boilerplate HTML (wie strukturierte Kartenkomponenten, Datentabellen oder gestylte Buttons) kann in ein einzelnes benutzerdefiniertes Element eingekapselt werden.
  • Erzwingen Sie Design Consistency – Ein benutzerdefinierter oder Tag-Helfer kann konsistente CSS-Klassen, Zugänglichkeitsattribute und Datenbindungsmuster erzwingen, wodurch die Wahrscheinlichkeit von UI-Inkonsistenzen verringert wird.
  • Verbessere die Lesbarkeit der Ansicht – Anstelle von verschachtelten s und bedingten C#-Blöcken ist ein einzelnes Tag mit einigen Attributen viel einfacher zu scannen und zu pflegen.
  • Unit Testing of View Logic – Da Tag-Helfer einfache Klassen sind, die HTML produzieren, können Sie Unit-Tests schreiben, um die erzeugte Ausgabe für verschiedene Eingaben zu überprüfen, was mit Inline-Razor-Code schwierig zu erreichen ist.
  • Erhöht die Wiederverwendbarkeit über Projekte hinweg – Eine Bibliothek mit benutzerdefinierten Tag-Helfern kann als NuGet-Komponente verpackt und über mehrere Lösungen hinweg geteilt werden, wodurch ein konsistentes UI-Toolkit gefördert wird.

Erstellen eines Basic Custom Tag Helpers

Jeder benutzerdefinierte Tag-Helfer erbt von der Klasse (oder implementiert direkt) und ist mit dem -Attribut dekoriert, um anzugeben, welches HTML-Element oder Attribut es anvisiert.

Schritt 1: Definieren Sie die Tag Helper Class

Erstellen Sie eine neue C#-Klasse in Ihrem Projekt, normalerweise in einem Ordner , erben Sie von und wenden Sie das -Attribut mit dem Elementnamen an, den Sie in Ihren Ansichten verwenden möchten.

[HtmlTargetElement("custom-card")]
public class CustomCardTagHelper : TagHelper
{
 public string Title { get; set; }
 public string CssClass { get; set; } = "card-default";

 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 // Replace the custom tag with a div and add the desired structure
 output.TagName = "div";
 output.Attributes.SetAttribute("class", $"card {CssClass}");

 // Build inner content
 output.Content.SetHtmlContent(
 $@"<div class=""card-header"">{Title}</div>
 <div class=""card-body"">
 {output.Content.GetContent()}
 </div>"
 );
 }
}

Schritt 2: TagHelperContext und TagHelperOutput verstehen

Das bietet Informationen über das aktuelle Element und seine Attribute. Das ermöglicht es Ihnen, den Tagnamen, die Attribute und den Inhalt des Elements zu ändern. Sie können auch für Klartext oder für Roh-HTML verwenden. Um den ursprünglichen Inhalt (z. B. Child-Elemente innerhalb des benutzerdefinierten Tags) zu erhalten, rufen Sie auf, wie oben gezeigt.

Schritt 3: Registrieren Sie den Tag Helper

Wenn sich Ihre Tag-Helfer in einer separaten Klassenbibliothek befinden, müssen Sie eine -Direktive in hinzufügen:

@addTagHelper *, MyApp.TagHelpers

Das Format ist oder eine Platzhalterung mit , um alle Tag-Helfer aus dieser Assembly einzuschließen.

Schritt 4: Verwenden Sie den Tag Helper in einer Razor-Ansicht

Mit der Registrierung können Sie das benutzerdefinierte Element verwenden:

<custom-card title="Welcome" css-class="card-primary">
 This is the body content
</custom-card>

Dies führt zu:

<div class="card card-primary">
 <div class="card-header">Welcome</div>
 <div class="card-body">
 This is the body content
 </div>
</div>

Erweiterte Tag Helper Techniken

Verwenden von Attributen und Property Binding

Benutzerdefinierte Tag-Helfer können mehrere Attribute akzeptieren, einschließlich komplexer Typen und Modellausdrücke, z. B. ein Tag-Helfer, der eine Formulareingabe wiedergibt, kann eine Eigenschaft an einen Modellausdruck binden:

[HtmlTargetElement("email-input")]
public class EmailInputTagHelper : TagHelper
{
 [HtmlAttributeName("asp-for")]
 public ModelExpression For { get; set; }

 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 output.TagName = "input";
 output.Attributes.SetAttribute("type", "email");
 output.Attributes.SetAttribute("id", For.Name);
 output.Attributes.SetAttribute("name", For.Name);
 output.Attributes.SetAttribute("value", For.Model?.ToString() ?? "");
 }
}

Das -Attribut bildet die C#-Eigenschaft einem bestimmten HTML-Attributnamen zu. Mit erhalten Sie Zugriff auf die Modellmetadaten für die vollständige Integration mit Validierungs- und Anzeigelogik.

Asynchrone Verarbeitung

Wenn Ihr Tag-Helfer E/A-Operationen durchführen muss (z. B. Daten aus einer Datenbank abrufen), überschreiben Sie stattdessen :

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
 var data = await _someService.GetDataAsync();
 output.Content.SetHtmlContent(data);
}

Dependency Injection bei Tag-Helfern

Tag-Helfer unterstützen die Konstruktor-Injektion wie jeder andere MVC-Service. Fügen Sie einfach Ihre Abhängigkeit zum Konstruktor hinzu, und der DI-Container löst sie auf:

public class UserProfileTagHelper : TagHelper
{
 private readonly IUserService _userService;

 public UserProfileTagHelper(IUserService userService)
 {
 _userService = userService;
 }

 public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
 {
 var user = await _userService.GetCurrentUserAsync();
 // render user profile markup
 }
}

Beachten Sie, dass Tag-Helfer standardmäßig vorübergehend sind; für jede Verwendung in einer Ansicht wird eine neue Instanz erstellt.

Tag Helper Components für Global HTML Injection

Mit den in ASP.NET Core 2.1 eingeführten Tag Helper Components können Sie Markup in jede Antwort weltweit einfügen, die typischerweise für die Bündelung von Skripten, Stilen oder Analysen verwendet wird. Erstellen Sie eine Klasse, die implementiert und registrieren Sie sie in :

public class GlobalScriptTagHelperComponent : TagHelperComponent
{
 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 if (output.TagName == "body" && output.Attributes.ContainsName("data-scripts"))
 {
 output.PostContent.AppendHtml("<script src='/js/global.js'></script>");
 }
 }
}

// In Startup.ConfigureServices
services.AddTransient<ITagHelperComponent, GlobalScriptTagHelperComponent>();

Praktische Beispiele für die Darstellung Zusammensetzung

1. Bedingter Wrapper Tag Helfer

Wrap content with an additional element only if a condition is met, nützlich für responsive layout container:

[HtmlTargetElement("if-wrapper")]
public class IfWrapperTagHelper : TagHelper
{
 public bool Condition { get; set; }

 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 if (!Condition)
 {
 // Remove the wrapping element, output only the child content
 output.TagName = null;
 output.Content.SetContent(output.Content.GetContent());
 }
 else
 {
 output.TagName = "div";
 output.Attributes.SetAttribute("class", "wrapper");
 }
 }
}

2. Bild mit Lazy Loading und Srcset

Erstellen Sie einen Tag-Helfer, der responsive -Tags mit -Attribut und mehreren Quellen generiert:

[HtmlTargetElement("lazy-image")]
public class LazyImageTagHelper : TagHelper
{
 public string Src { get; set; }
 public string Srcset { get; set; }
 public string Alt { get; set; }
 public string CssClass { get; set; }

 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 output.TagName = "img";
 output.Attributes.SetAttribute("src", Src);
 if (!string.IsNullOrEmpty(Srcset))
 output.Attributes.SetAttribute("srcset", Srcset);
 output.Attributes.SetAttribute("alt", Alt);
 output.Attributes.SetAttribute("loading", "lazy");
 if (!string.IsNullOrEmpty(CssClass))
 output.Attributes.SetAttribute("class", CssClass);
 }
}

3. Validierungszusammenfassung mit Custom Structure

Anstatt den integrierten Validierungs-Summulations-Tag-Helfer zu verwenden, erstellen Sie einen, der benutzerdefinierte Symbole und Stylings hinzufügt:

[HtmlTargetElement("custom-validation-summary")]
public class CustomValidationSummaryTagHelper : TagHelper
{
 [HtmlAttributeName("asp-validation-summary")]
 public ValidationSummary ValidationSummary { get; set; }

 [ViewContext]
 public ViewContext ViewContext { get; set; }

 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
 var viewData = ViewContext.ViewData;
 var errors = viewData.ModelState.Where(s => s.Value.Errors.Count > 0).SelectMany(s => s.Value.Errors).ToList();

 if (errors.Count == 0)
 {
 output.SuppressOutput();
 return;
 }

 output.TagName = "div";
 output.Attributes.SetAttribute("class", "alert alert-danger");
 var list = new StringBuilder();
 list.Append("<ul class='mb-0'>");
 foreach (var error in errors)
 {
 list.Append($"<li><strong>Error:</strong> {error.ErrorMessage}</li>");
 }
 list.Append("</ul>");
 output.Content.SetHtmlContent(list.ToString());
 }
}

Best Practices für den Aufbau von Tag-Helfern

  • Halten Sie die C#-Logik minimal – Tag-Helfer sind für die Präsentationstransformation, nicht für die Geschäftslogik.
  • Favor for I/O – Auch wenn Ihre aktuelle Implementierung synchron ist, erleichtert die Verwendung von das spätere Hinzufügen von Async-Aufrufen, ohne Änderungen zu unterbrechen.
  • Verwende beschreibende Namen für benutzerdefinierte Elemente – Befolge eine Konvention wie oder , um Kollisionen mit zukünftigen HTML-Standards zu vermeiden.
  • Leverage – Für interne Eigenschaften, die nicht vom Markup festgelegt werden sollten, markieren Sie sie mit diesem Attribut.
  • Testen Sie die generierte HTML – Schreiben Sie Unit-Tests, die den Tag-Helfer instantiieren, aufrufen und die Ausgabe mit -Behauptungen überprüfen.
  • Betrachten Sie die Zugänglichkeit – Fügen Sie ARIA-Attribute und gegebenenfalls die Tastaturunterstützung hinzu.

Häufige Fallstricke und Fehlersuche

  • Tag Helfer nicht entdeckt werden – Stellen Sie sicher, dass die Direktive in auf die korrekte Assembly verweist.
  • Attributnamen, die nicht übereinstimmen – Verwenden Sie das -Attribut, um C#-Eigenschaftsnamen HTML-Attributnamen zuzuordnen.
  • Inhalt nicht rendern – Wenn Sie aufrufen, bevor Sie Kinderinhalte abrufen, verlieren Sie das ursprüngliche innere HTML.
  • Mehrere Tag-Helfer, die auf dasselbe Element zielen – Die Ausführungsreihenfolge folgt standardmäßig der alphabetischen Reihenfolge, kann aber mit der -Eigenschaft gesteuert werden.
  • Abhängigkeits-Injektionsprobleme – Tag-Helfer sind nicht Singleton-Scoped. Wenn Sie einen Scoped-Dienst einfügen, stellen Sie sicher, dass der Tag-Helfer innerhalb des gleichen HTTP-Anfragebereichs verbraucht wird (normalerweise ist er es).

Integrieren von Custom Tag-Helfern in eine bestehende Codebase

Die Einführung von benutzerdefinierten Tag-Helfern erfordert keine vollständige Neufassung. Sie können damit beginnen, die sich wiederholenden Muster – wie Schaltflächen, Karten oder Datentabellen – in Tag-Helfer umzugestalten. Im Laufe der Zeit werden Sie eine Bibliothek erstellen, die zur einzigen Wahrheitsquelle für Ihre UI-Komponenten wird. Kombinieren Sie Tag-Helfer mit anderen Kompositionstools wie Partials und Ansichtskomponenten für maximale Flexibilität. Zum Beispiel könnte eine Ansichtskomponente komplexe Daten abrufen und sie dann an einen Tag-Helfer weitergeben, um das endgültige HTML zu rendern.

Externe Ressourcen und weitere Lesung

Schlussfolgerung

Benutzerdefinierte Tag-Helfer stellen eine bedeutende Entwicklung in der Art und Weise dar, wie Entwickler Ansichten in ASP.NET Core MVC erstellen. Indem Sie Ihre eigenen HTML-Elemente und Attribute definieren können, die serverseitige Logik ausführen, schließen sie die Lücke zwischen Designer-freundlichem Markup und Programmierer-Steuerung. Von einfachen Tastengeneratoren bis hin zu komplexen, zustandsbewussten Komponenten, die mit Abhängigkeitsinjektion integriert sind, ermöglichen Tag-Helfer Ihnen, wartbare, testbare und konsistente Benutzeroberflächen zu erstellen. Starten Sie klein - Refactor ein einzelnes wiederholtes Muster in einen Tag-Helfer - und Sie werden bald sehen, wie diese Technik Ihre Ansichtsschicht zum Besseren transformiert.