Laden...

Wieso validiert eine RegularExpression Annotation immer zu false?

Erstellt von Davaaron vor 3 Jahren Letzter Beitrag vor 3 Jahren 575 Views
D
Davaaron Themenstarter:in
106 Beiträge seit 2016
vor 3 Jahren
Wieso validiert eine RegularExpression Annotation immer zu false?

Hi,

ich würde gerne ein paar Constraints für meine Domain-Models angeben per Annotation.
Für eine double-Property habe ich die Voraussetzung, die Zahl nach dem Schema "####.##" aufgebaut ist, also maximal 4 Dezimalstellen und 2 Nachkommastellen hat.
Als valide würde ich beispielsweise
255.5
255.55
.55
2.55
2.5
255.
bezeichnen.

Meine Annotation sieht so aus:


[RegularExpression(@"\d{1,4}(\.\d{0,2})?", ErrorMessage = "Invalid property (4/2)")]
public double Property{ get; set; }

Die Methode zum Validieren sieht wie folgt aus (alle Models bekommen per Vererbung die Methode zur Verfügung gestellt, daher ist "this" das aktuelle konkrete Objekt)


public (bool isValid, List<ValidationResult> validationResults) Validate()
{
    var context = new ValidationContext(this, serviceProvider: null, items: null);
    var validationResults = new List<ValidationResult>();

    bool isValid = Validator.TryValidateObject(this, context, validationResults, true);
    return (isValid, validationResults);
}

Wenn ich nun Validate aufrufe, bekomme ich immer false.


var obj = new MyObject(); //erbt die Methode Validate()
obj.Property = 255.55;
var val = obj.Validate();
Console.WriteLine(val.isValid); // = false

Wieso?

Wenn ich das ganze manuell mache mit Regex, dann funktioniert es einwandfrei, hier mal ein paar Beispiele:


var regexp3 = @"\d{1,4}(\.\d{0,2})?";
            Regex re3 = new Regex(regexp3);
            var m7 = re3.IsMatch("-120");
            var m8 = re3.IsMatch("200.55");
            var m9 = re3.IsMatch("200.5");
            var m10 = re3.IsMatch("200.");
            var m11 = re3.IsMatch(".33");
            var m12 = re3.IsMatch("100");

16.806 Beiträge seit 2008
vor 3 Jahren

Die Info hast Du vergessen; aber offenbar validierst Du gegen ASP.NET Core (oder wieso ValidationContext?); und hier kann ich Dir nur FluentValidation absolut und stark empfehlen.
Hier geht das über die ScalePrecision.

Beachte bei Deiner Validierung, dass Du einen fixen Punkt als Dezimal-Wert verwendest und die Culture gar nicht beachtest.

PS: ich bin kein Fan von Annotations an den Domain Models. In modernen Software Architekturen (zB Reactive Architecture) hast Du an vielen Stellen keine Domain Models auf Code-Ebene mehr.
Typischer Fall für sowas ist eigentlich das entgegennehmen von Eingaben - dafür wurden sie zumindest konzipiert.

D
Davaaron Themenstarter:in
106 Beiträge seit 2016
vor 3 Jahren

Eigentlich ist es eine .NET 4.7 Konsolenapplikation. ValidationContext habe ich als "Built-In" Klasse gefunden (kommt ja von System.ComponentModel.DataAnnotations). Mich wundert es nur, dass die Built-In Validierung nicht wirklich zu funktionieren scheint. Andere Annotations habe ich noch nicht ausprobiert.

Die Annotation gefallen mir besser als alles "fluent" zu schreiben. Nuget Pakete wollte ich eigentlich vermeiden. Wollte mal sehen, was Microsoft so zu bieten hat und wie es "von Haus aus" funktioniert.

16.806 Beiträge seit 2008
vor 3 Jahren

Verstehe die Haltung nicht NuGet Pakete zu vermeiden; wo ist der sinn?
So funktioniert auch das .NET Ökosystem nicht. Die Zeiten, dass Microsoft die super Ideen aus der Community übernimmt und damit Konkurrenz für Open Source Projekte aufbaut; die sind vorbei.
Stattdessen wirbt Microsoft für Open Source und Open Source Projekte.

PS: alle neuen Microsoft Libs werden ebenfalls über NuGet verteilt.
Geht gar nicht mehr ohne.

Data Annotations kommen ursprünglich von ASP.NET MVC, kamen dann in EF und dann in den Rest vom Framework; daher auch natürlich der Namespace.
Aus duesem Grund auch die Frage und entsprechend die potentielle Verwendung des Kontext.

Hast Du aber kein ASP.NET Context, dann kannst Du Fluent Validations so ohne weiteres auch nicht verwenden.

Aber zum Problem:
Deine Validierung auf dieser Basis nicht erfolgen, weil die Regex Annotation nur gegen ein String funktionieren kann und nicht gegen ein Double.
Macht auch kein Sinn Regex gegen ein Double laufen zu lassen, wenn das Format der Annotation völlig unbekannt ist.
Das ist nicht vergleichbar mit Deinem manuellen Regex.

Musst entweder einen völlig eine eigene Annotation schreiben oder ein String entgegen nehmen.

D
Davaaron Themenstarter:in
106 Beiträge seit 2016
vor 3 Jahren

Stimmt, stimmt. Vieles wird über Nuget Pakete importiert. Trotzdem wollte ich es mal mit einer Microsoft Lösung versuchen. Beim Loggen benutze ich auch immer Serilog oder NLog, wobei es eine Microsoft Lösung gibt. Aber ja, ich gucke mir gerade FluentValidation an, das wird ja hoch gelobt.

Die Erklärung mit dem Double vs String macht Sinn. Dachte der validiert auch gegen Doubles, aber das erklärt, warum es nicht funktioniert.

16.806 Beiträge seit 2008
vor 3 Jahren

Serilog oder NLog, wobei es eine Microsoft Lösung gibt.

Ne, gibt keine direkte Lösung von Microsoft für Full Structured Logging im genaueren Sinne.
Es gibt nur den ILogger-Provider mit einer Standard-Implementierung, den Du dann adaptieren kannst (wie es zB Serilog oder NLog machen).
Die zur Verfügung stehenden Implementierungen sind nur rudimentär.

Aber das ist ein anderes Thema.

Aber was halt nicht sinnvoll ist: Du vermisst im Endeffekt das Format der Eingabe mit der Value in der Runtime.
Gerade wenn es darum geht Business Modelle zu validieren sollte Dir das Format völlig egal sein.

Ein Range in der Logik zu validieren macht Sinn; ein Format gewiss nicht.

D
Davaaron Themenstarter:in
106 Beiträge seit 2016
vor 3 Jahren

Mit ScalePrecision habe ich es nicht hinbekommen. Wenn ich es richtig verstehe, geht das aber auch schlecht. Allerdings konnte ich dort mein Regex einfügen und die Validierung funktioniert. Natürlich zuerst in ein string umwandeln.

Bei der Microsoft Annotation Lösung habe ich meinen double gegen ein string getauscht und es hat dennoch nicht funktioniert.