ASP.NET Core:crea un attributo di convalida del modello personalizzato

ASP.NET Core:crea un attributo di convalida del modello personalizzato

Sono disponibili molti attributi di convalida del modello integrati, come [Richiesto] e [Intervallo], che puoi utilizzare per gestire la maggior parte degli scenari di convalida. Quando questi non sono sufficienti, puoi creare un attributo di convalida personalizzato con la tua logica di convalida. Mostrerò un esempio di come farlo.

1 – Sottoclasse ValidationAttribute e implementa la logica di convalida

Per creare un attributo di convalida del modello personalizzato, la sottoclasse ValidationAttribute, sovrascrivere il metodo IsValid() e implementare la logica di convalida. Ecco un esempio:

using System.ComponentModel.DataAnnotations;

public class FutureDateTimeAttribute : ValidationAttribute
{
	public override bool IsValid(object value)
	{
		if (value is DateTimeOffset dateTimeOffset && dateTimeOffset > DateTimeOffset.Now)
			return true;
	
		return false;
	}
}
Code language: C# (cs)

Quando arriva una richiesta (e stai usando l'attributo su una proprietà), il framework chiama automaticamente IsValid() con l'oggetto proprietà durante la fase di convalida del modello. Se restituisce false, la convalida non riesce e restituisce una risposta di errore di convalida.

Nota:poiché questa logica viene eseguita potenzialmente su ogni richiesta (quando viene utilizzato l'attributo), mantieni la tua logica di convalida il più leggera possibile.

2 – Modifica il messaggio di errore (opzionale)

La risposta di errore predefinita è simile alla seguente:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "0HMHK72C15DT8:0000000B",
    "errors": {
        "Showtime": [
            "The field Showtime is invalid."
        ]
    }
}
Code language: JSON / JSON with Comments (json)

Il messaggio di errore predefinito:"Il campo non è valido" – è piuttosto vago. Se vuoi fornire un messaggio di errore più specifico, un'opzione è sovrascrivere il metodo FormatErrorMessage() e codificare il messaggio di errore (con il nome della proprietà al suo interno):

using System.ComponentModel.DataAnnotations;

public class FutureDateTimeAttribute : ValidationAttribute
{
	public override bool IsValid(object value)
	{
		if (value is DateTimeOffset dateTimeOffset && dateTimeOffset > DateTimeOffset.Now)
			return true;
	
		return false;
	}
	public override string FormatErrorMessage(string name)
	{
		return $"{name} must be a future date";
	}
}
Code language: C# (cs)

L'hardcoding del messaggio di errore come questo va bene se stai creando un attributo di convalida molto specifico.

Se stai creando un attributo di convalida generico, puoi utilizzare il ErrorMessage per consentire la specificazione del messaggio di errore dall'esterno. L'override di FormatErrorMessage() è facoltativo.

Nota:fai attenzione se prevedi di utilizzare string.Format() con ErrorMessage. Questa è una ricetta per FormatException di runtime.

3 – Usa l'attributo

Per utilizzare l'attributo, incollalo su una proprietà del modello:

public class MovieTicketOrder
{
	public string Movie { get; set; }
	public int Seats { get; set; }

	[FutureDateTime]
	public DateTimeOffset? Showtime { get; set; }
}
Code language: C# (cs)

Nota:la logica di convalida controlla "l'oggetto è DateTimeOffset", che è falso se l'oggetto è null o non è un DateTimeOffset. Ecco perché sta usando una proprietà nullable qui.

Invia una richiesta con un valore che non dovrebbe essere convalidato (al momento dell'invio, questo è un datetime passato):

POST /movies/buytickets

{
    "movie": "Doctor Strange in the Multiverse of Madness",
    "seats": 2,
    "showtime": "2022-05-12T13:00-04:00"
}
Code language: plaintext (plaintext)

Ciò si traduce correttamente in un 400 – Richiesta non valida con una risposta di errore di convalida:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "0HMHK8RVAMMQN:00000001",
    "errors": {
        "Showtime": [
            "Showtime must be a future date"
        ]
    }
}
Code language: JSON / JSON with Comments (json)

Ora invia una richiesta con un valore che dovrebbe superare la convalida (al momento in cui sto inviando questo, questo è un datetime futuro):

POST /movies/buytickets

{
    "movie": "Doctor Strange in the Multiverse of Madness",
    "seats": 2,
    "showtime": "2022-05-12T19:00-04:00"
}
Code language: plaintext (plaintext)

Ciò si traduce in un 200 – OK risposta poiché ha superato correttamente la convalida.