Voglio condividere con te un modo molto rapido ed efficace per validare le proprietà delle tue classi c#. Come ben sai Data Annotations facilita enormemente la validazione dei valori memorizzati nelle proprietà delle tue classi. Tipicamente queste sono dei DTO che viaggiano tra il layer UI della tua applicazione ed i layer sottostanti.
Molti sfruttano Data Annotations solo in ambito ASP.NET MVC ma questa comoda infrastruttura, con un piccolo setup è utilizzabile in ogni tipo di progetto da Windows Forms a WPF fino addirittura ad una Console Application.
Per prima cosa scriviamo la nostra classe. Il Name verrà validato alla vecchia maniera, mentre le altre 3 proprietà verranno semplicemente decorate con il loro attributo di validazione:
class Player
{
string name;
public string Name { get => name; set => name = ValidateName(value); }
[Range(0,100)]
public int Age { get; set; }
[EmailAddress]
public string Email { get; set; }
[Required]
[Phone]
public string Phone { get; set; }
string ValidateName(string v)
{
if (string.IsNullOrWhiteSpace(v) || v.Length < 2 || v.Length > 50)
throw new ArgumentException("Name is invalid");
return v;
}
public override string ToString() => $"Name:{Name} Age:{Age}";
public override bool Equals(object obj) => obj is Player
&& ((Player)obj).Age == Age
&& ((Player)obj).Name == Name;
}
Adesso scriviamo il nostro Extension Method per consentirci di eseguire la validazione:
public static class DataAnnotationsValidator
{
public static bool TryValidate(this object @object, out ICollection results)
{
var context = new ValidationContext(@object, serviceProvider: null, items: null);
results = new List();
return Validator.TryValidateObject(
@object, context, results,
validateAllProperties: true
);
}
}
Ed infine scriviamo il nostro Test per capire come gira il tutto:
[TestMethod]
public void PropertyConstraintsTest()
{
var p = new Player();
// standard validation
Assert.ThrowsException(() => p.Name = "a");
// data annotations validation
ICollection validationResults;
p.Phone = "+39347096744";
p.Age = 103;
Assert.IsFalse(p.TryValidate(out validationResults));
Assert.IsTrue(validationResults.First().MemberNames.Contains("Age"));
p.Age = 43;
Assert.IsTrue(p.TryValidate(out validationResults));
Assert.IsTrue(validationResults.Count() == 0);
p.Email = "pino";
Assert.IsFalse(p.TryValidate(out validationResults));
Assert.IsTrue(validationResults.First().MemberNames.Contains("Email"));
p.Email = "pino@pino.com";
Assert.IsTrue(p.TryValidate(out validationResults));
Assert.IsTrue(validationResults.Count() == 0);
p.Phone = "";
Assert.IsFalse(p.TryValidate(out validationResults));
Assert.IsTrue(validationResults.First().MemberNames.Contains("Phone"));
}
Come puoi vedere questo metodo velocizza enormemente il tuo modo di validare le entità, anche nei livelli sottostanti alla UI. L'unica criticità è legata al fatto che dovrai OBBLIGATORIAMENTE eseguire il metodo TryValidate prima di rendere disponibile la tua entità ad altri layer, come ad esempio prima di passarla Data Layer per l'inserimento nel Database.
#
programming #
tricks #
csharp