Die Datenannotation im Namensraum System.ComponentModel.DataAnnotations
gibt es schon seit dem klassischen .NET Framework. Die ersten wie [RegularExpression]
, [Range]
oder [DataType]
wurden in .NET Framework 3.5 eingeführt. Weitere Datenannotation folgten in .NET Framework 4.0 (z. B. [Display]
und [Editable]
) und .NET Framework 4.5 (z. B. [MaxLength]
, [Compare]
, [CreditCard]
und [Phone]
). Diese Datenannotation lassen sich auf Klassen oder Properties beziehungsweise Fields verwenden. Sie dienen der Spezifikation der Darstellung (z. B. [Display]
und [Editable]
) oder der Validierung von Werten (z.B. [RegularExpression]
, [Compare]
, [Range]
, [Phone]
und [CreditCard]
). GUI-Steuerelemente müssen die entsprechenden Annotationen berücksichtigen.
Es gibt nur wenige Steuerelemente, die die Darstellungsannotationen berücksichtigen – meist schaffen sich .NET-Entwicklerinnen und -Entwickler hier selbst Steuerelemente, die auf Basis der in den Annotationen abgelegten Metadaten eine grafische Benutzeroberfläche on the fly zur Laufzeit erzeugen. Bei den Validierungsannotationen gibt es mehr Steuerelemente, die die Annotationen berücksichtigen, darunter <InputText>
, <InputNumber>
und <InputDate>
in Blazor. Eine Validierung kann man auch unabhängig von einem Steuerelement im Programmcode ausführen. Dazu gibt es die Klassen ValidationContext
, Validator
, ValidationResult
und ValidationException
.
Neue Eigenschaften in .NET 8.0
Die [Range]
-Annotation besitzt in .NET 8.0 die zusätzlichen Eigenschaften MinimumIsExclusive
und MaximumIsExclusive
, um die genannte Unter- und Obergrenze selbst als gültigen Werte auszuschließen. Standard ist wie bisher, dass die Grenzen eingeschlossen sind.
Neue Annotationen in .NET 8.0
Zudem hat Microsoft drei neue Annotationsklassen ergänzt:
- Die neue Annotation
[Length]
kann verwendet werden, um die Mindest- und Maximallänge von Objektmengen und Zeichenketten zu setzen. - Mit der neuen Annotation
[Base64String]
prüft man, ob eine Zeichenkette Base64-codiert ist. - Mit
[AllowedValues]
und [DeniedValues]
kann man eine Liste erlaubter Werte für Properties eines Objekts angeben. Das funktioniert allerdings nur den Werten in einzelnen Properties oder Fields; auf Objektmengen angewendet wirken diese beiden Annotationen leider nicht.
Das nächste Listing zeigt ein aussagekräftiges Beispiel zu allen neuen Annotationsfeatures anhand der Klasse SoftwareArchitect
mit einigen annotierten Eigenschaften. Die Validierung wird durchgeführt mit den Klassen ValidationContext
und Validator
.
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using ITVisions;
using NET8_Console.CustomAnnotations;
namespace NET8_Console.FCL_Annotations;
/// <summary>
/// Neue und erweiterte Annotationen zur Validierung
/// </summary>
public class SoftwareArchitect
{
// Neu in .NET 8.0 --> Nicht als Anrede erlaubt:
[DeniedValues("", "Dr.", "Prof. Dr.")]
public string? Anrede { get; set; }
// Neu in .NET 8.0 --> Erlaubte Titel:
[AllowedValues("", "Dr.", "Prof. Dr.")]
public string? Titel { get; set; }
// funktioniert hier nicht, da es sich um eine Liste handelt:
[AllowedValues("C#", "Java", "JavaScript")]
public List<string> Sprachen { get; set; } = new();
// Neu in .NET 8.0: Unter- und Obergrenze für Zeichenkettenlänge:
[Length(2, 50)]
public string? Name { get; set; }
// Neu in .NET 8.0: Unter- und Obergrenze für Mengenlänge:
[Length(0, 3)]
public List<string> Websites { get; set; } = new();
// Neu in .NET 8.0:
[Base64String]
public string? Token { get; set; }
// MinimumIsExclusive und MaximumIsExclusive
// sind neu seit .NET 8.0
// > 0 und < 120 statt >= und <=:
[Range(0d, 120d, MinimumIsExclusive = true,
MaximumIsExclusive = true)]
public double Alter { get; set; }
#endregion
}
public class FCL_Annotations_Demo
{
public void Run()
{
CUI.H2(nameof(FCL_Annotations_Demo));
// Das zu validierende Objekt erstellen
SoftwareArchitect hs = new()
{
Name = "Holger Schwichtenberg",
Titel = "Doktor",
Anrede = "",
Token = "unsinn"
};
hs.Websites.Add("www.IT-Visions.de");
hs.Websites.Add("www.dotnet-doktor.de");
hs.Websites.Add("www.entwickler-lexikon.de");
hs.Websites.Add("www.dotnet7.de");
hs.Websites.Add("www.dotnet8.de");
hs.Sprachen.Add("C#");
hs.Sprachen.Add("JavaScript");
hs.Sprachen.Add("TypeScript");
// Validierung vorbereiten
var ctx = new ValidationContext(hs);
var results = new List<ValidationResult>();
// Validierung durchführen
if (!Validator.TryValidateObject(hs, ctx, results, true))
{
CUI.Error($"{results.Count} errors validating the objects:");
// Fehler ausgeben
foreach (var validationResult in results)
{
CUI.LI(validationResult.ErrorMessage, ConsoleColor.Red);
}
}
else
{
// Es war alles OK
CUI.Success("Validation succeeded!");
}
}
}
Beim Ausführen des Programmcodes im obigen Listing mit .NET 8.0 kommt es zu sechs Validierungsfehlern
(Bild: Screenshot von Holger Schwichtenberg)
(rme)