Benutzerdefiniertes ValidationAttribute und Blazor-Validierung
# Passen Sie alles individuell an
Wie Sie wahrscheinlich in all meinen Beiträgen gesehen haben, versuche ich wirklich, alles so sauber wie möglich zu halten, da ich bereits Beiträge zu benutzerdefinierten Attributen, benutzerdefinierter Ausnahmebehandlung, Service-Collection-Injection usw. geschrieben habe.
Mit der Zeit habe ich erkannt, dass diese Art der Codierung mir und meinem Team die Möglichkeit bietet, Überstunden zu verbessern, Probleme einfacher zu finden und den Code so weit wie möglich zu trennen.
Ja, nach dieser coolen Geschichte, die ich gerade habe, habe ich in letzter Zeit wie üblich an Blazor gearbeitet und festgestellt, dass man nach vielen Jahren der Entwicklung benutzerdefinierte Validierungsattribute erstellen kann.
Ja, es ist lustig, nach all den Jahren …
Benutzerdefinierte Validierungsattribute
Die Idee kam eigentlich aus der Arbeit, wir führen immer eine Validierung an allen Stellen durch, aber ich hatte einige Felder, die den gleichen Validierungsprozess erforderten, also dachte ich, dass da vielleicht etwas dabei sein könnte … zum Beispiel benutzerdefinierte Validierungsattribute!
Also habe ich die Microsoft-Dokumentation dafür aufgerufen und herausgefunden, dass man benutzerdefinierte Validierungsattribute erstellen und sie den Eigenschaften zuweisen kann, genau so:
public class StringLengthRangeAttribute : ValidationAttribute
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public StringLengthRangeAttribute()
{
this.Minimum = 0;
this.Maximum = int.MaxValue;
}
public override bool IsValid(object value)
{
string strValue = value as string;
if (!string.IsNullOrEmpty(strValue))
{
int len = strValue.Length;
return len >= this.Minimum && len <= this.Maximum;
}
return true;
}
}
und verwenden Sie es in einer einfachen Klasse wie dieser:
[Required]
[StringLengthRange(Minimum = 10, ErrorMessage = "Must be >10 characters.")]
[StringLengthRange(Maximum = 20)]
[Required]
[StringLengthRange(Minimum = 10, Maximum = 20)]
Benutzerdefinierter Validator
Ich habe also diesen Validator, den ich für einen bestimmten Geschäftsfall benötige, der 20 erste Zeichen enthält, die 9 Zahlen und einen Bindestrich enthalten, und mit 2 Zeichen endet, die normalerweise der Ländercode sind, also etwa so: 123456789-123456789-ES
Am Ende habe ich mir so etwas ausgedacht, es ist wirklich einfach, aber es funktioniert:
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
public class SpecialStringValidatorAttribute : ValidationAttribute
{
private const int TotalLength = 22;
private const string Pattern = @"^(\d{10})-(\d{10})-([A-Za-z]{2})$";
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string strValue = value as string;
if (!string.IsNullOrEmpty(strValue))
{
if (strValue.Length != TotalLength)
{
return new ValidationResult($"The string must be {TotalLength} characters long.");
}
if (!Regex.IsMatch(strValue, Pattern))
{
return new ValidationResult("The string must follow the pattern: 1234567890-1234567890-AB");
}
return ValidationResult.Success;
}
return new ValidationResult("The string cannot be null or empty.");
}
}
Tests
Für alle Fälle habe ich auch einen Test für sie geschrieben:
public class SpecialStringValidatorTests
{
[Theory]
[InlineData("1234567890-1234567890-AB", true)]
[InlineData("1234567890-1234567890-XY", true)]
[InlineData("1234567890-1234567890-A1", false)]
[InlineData("1234567890-1234567890-A", false)]
[InlineData("1234567890-123456789-AB", false)]
[InlineData("1234567890-1234567890", false)]
[InlineData("1234567890-1234567890-ABCDE", false)]
public void SpecialStringValidatorTest(string input, bool expectedResult)
{
// Arrange
var validator = new SpecialStringValidatorAttribute();
// Act
var result = validator.IsValid(input);
// Assert
Assert.Equal(expectedResult, result);
}
}
Und beim Ausführen hatte ich folgende Ergebnisse:
Microsoft (R) Test Execution Command Line Tool Version 16.9.1
Copyright (c) Microsoft Corporation. All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Test run in progress...
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-AB", expectedResult: True)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-XY", expectedResult: True)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-A1", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-A", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-123456789-AB", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890", expectedResult: False)
Passed! - SpecialStringValidatorTests.SpecialStringValidatorTest(input: "1234567890-1234567890-ABCDE", expectedResult: False)
Test Run Successful.
Total tests: 7
Passed: 7
Total time: 1.7296 Seconds
Benutzerdefinierte Validierung und Blazor
Da ich nun weiß, dass er verwendet werden kann, ist es eindeutig eine gute Idee, ihn in Blazor zu implementieren, oder?
Nehmen wir an, ich habe dieses Formular, das das zuvor gezeigte Modell Person verwendet:
@using Models
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
<EditForm Model=@Person FormName="PersonForm">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="form-group">
<label for="Name">Name</label>
<InputText @bind-Value=Person.Name class="form-control" id="Name" />
<ValidationMessage For="() => Person.Name"/>
</div>
<div class="form-group">
<label for="MySpecialString">My special string</label>
<InputText @bind-Value=Person.MySpecialString class="form-control" id="Name" />
<ValidationMessage For="() => Person.MySpecialString"/>
</div>
<div class="form-group">
<label for="Age">Age</label>
<InputNumber @bind-Value=Person.Age class="form-control" id="Age" />
<ValidationMessage For=@(() => Person.Age) />
</div>
<input type="submit" class="btn btn-primary" value="Save"/>
</EditForm>
@code {
Person Person = new Person();
}
Sobald wir dies ausführen, erhalten wir die folgenden Fehler:

Und wenn wir einfach das eingeben, was wir wollen, erhalten wir eindeutig Folgendes:

Um ehrlich zu sein, ist es für mich ganz klar, dass wir zumindest die Logik zur Validierung dieser Formulare in benutzerdefinierte Validierungsattribute verschieben sollten. Dadurch haben wir die Freiheit, den Code für diese Anmeldung an einem einzigen Ort zu speichern, und wir können ihn später für eine API oder eine andere Anwendung verwenden.
Ich hoffe, es hat Ihnen gefallen. Wenn Sie Fragen haben oder Kontakt mit mir aufnehmen möchten, zögern Sie nicht und kontaktieren Sie mich!