Aggiungendo alcuni metadati al tuo oggetto, ereditando da una classe astratta che contiene quei dati, scrivendo un oggetto composito o qualcosa di simile.
In ASP.NET MVC 1, questo sarebbe stato fatto allegando un partial class
alla tua entità (nel linguaggio C #, le classi che hanno lo stesso nome con il modificatore partial
davanti a loro sono semplicemente trattate come una grande singola classe).
Quindi, ad esempio:
public partial class Dinner {
public bool IsValid {
get { return (GetRuleViolations().Count() == 0); }
}
// Return a list of errors that we can iterate over with 'foreach'
public IEnumerable<RuleViolation> GetRuleViolations() {
// Validation rules go here; see below for an example.
yield break;
}
partial void OnValidate(ChangeAction action) {
if (!IsValid)
throw new ApplicationException("Rule violations prevent saving");
}
}
Una violazione delle regole è solo un oggetto immutabile contenente un messaggio di errore e un nome di proprietà:
public class RuleViolation {
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
public RuleViolation(string errorMessage, string propertyName) {
ErrorMessage = errorMessage;
PropertyName = propertyName;
}
}
Quindi verificherai errori come questo:
public IEnumerable<RuleViolation> GetRuleViolations() {
if (String.IsNullOrEmpty(Title))
yield return new RuleViolation("Title required","Title");
if (String.IsNullOrEmpty(Description))
yield return new RuleViolation("Description required","Description");
if (String.IsNullOrEmpty(HostedBy))
yield return new RuleViolation("HostedBy required", "HostedBy");
if (String.IsNullOrEmpty(Address))
yield return new RuleViolation("Address required", "Address");
if (String.IsNullOrEmpty(Country))
yield return new RuleViolation("Country required", "Country");
if (String.IsNullOrEmpty(ContactPhone))
yield return new RuleViolation("Phone# required", "ContactPhone");
if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
yield return new RuleViolation("Phone# does not match country", "ContactPhone");
yield break;
}
Questa disposizione consente di riportare gli errori a una vista in modo che possano essere visualizzati all'utente, in questo modo (Questo è un metodo di controller, accetta un modulo POST da un modulo Web utente):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
// Map form fields to dinner object
UpdateModel(dinner);
// Validation occurs here. Throws exception if validation fails
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
// Add each rule violation to the View, so that errors can be displayed.
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
// Display form with validation errors.
return View(dinner);
}
}
Si noti che l'eccezione è lì solo per attivare il processo di gestione della convalida; non esiste un'eccezione per ogni possibile errore di convalida. Invece, le regole di convalida sono codificate nel metodo GetRuleViolations()
e vengono tutte gestite contemporaneamente.
Naturalmente, al giorno d'oggi, il processo è diventato un po 'più raffinato. Nelle versioni più recenti di ASP.NET MVC, gli attributi vengono utilizzati per codificare le regole di convalida. Ma il principio è sempre lo stesso: non si usano eccezioni per codificare le singole regole di convalida. Nota i metadati di convalida che sono codificati negli attributi del codice sottostante (gli attributi sono quelle righe di codice che sono racchiuse tra parentesi):
public class Movie
{
public int ID { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
[StringLength(5)]
public string Rating { get; set; }
}