ASP.NET Core Blazor validación de formularios en el lado cliente en SSR estático

En este artículo se explica cómo Blazor agrega la validación dinámica del lado cliente a los formularios que usan la representación estática del lado servidor (SSR estático). El explorador valida los campos individuales a medida que el usuario los edita y valida el formulario completo antes de enviarlo. Si se supera la comprobación del lado cliente, el formulario se envía y se valida de nuevo en el servidor.

Los formularios que usan un modo de representación interactiva no usan la característica estática de validación del lado cliente de SSR que se describe en este artículo. Tanto la validación por campo como la validación del envío del formulario completo se ejecutan en .NET a través del EditContext del formulario.

Funcionamiento de la validación del lado cliente

Cuando un formulario SSR estático contiene un DataAnnotationsValidator componente, Blazor representa las reglas de validación del formulario en la página y las aplica mediante JavaScript antes de enviar el formulario. El usuario ve errores de validación sin necesidad de enviar la solicitud al servidor y esperar la respuesta.

La validación del lado cliente se activa automáticamente cuando se cumplen las condiciones siguientes:

Para el conjunto integrado de atributos de validación, no se requiere ninguna configuración de JavaScript, paquete adicional o registro de servicio. En la sección Reglas de validación personalizadas del lado cliente se describe cómo agregar compatibilidad con atributos de validación personalizados.

Importante

La validación del lado cliente es una mejora de la experiencia del usuario, no un pase de validación autoritativo. Se puede omitir deshabilitando o modificando la ejecución de JavaScript del explorador. La validación del lado servidor se ejecuta después de publicar el formulario y sigue siendo autoritativa. Nunca confíe en la validación del lado cliente para proteger la integridad de los datos.

Atributos de validación admitidos

Los atributos siguientes System.ComponentModel.DataAnnotations se aplican en el lado cliente y coinciden con el comportamiento de las anotaciones de datos del lado servidor:

Los atributos de validación que no aparecen en esta lista, incluidos los atributos derivados personalizados ValidationAttribute, no se aplican en el lado cliente de forma predeterminada. Siguen ejecutándose en el servidor después de enviar el formulario. Para proporcionar una regla del lado cliente para un atributo personalizado, consulte la sección Reglas de validación personalizadas del lado cliente .

Tiempo de validación

Un campo se valida cuando se confirma su valor. En el caso de las entradas de texto (<input> elementos), esto se produce cuando el campo pierde el foco. Las casillas y las listas desplegables se validan inmediatamente después de la selección.

Después de que un campo haya mostrado un error de validación o después de que el formulario se haya enviado al menos una vez, el campo se valida de nuevo en cada pulsación de tecla para que las correcciones se reflejen inmediatamente.

El envío del formulario valida cada campo de seguimiento. Si algún campo no es válido, el envío se bloquea y el foco se mueve al primer campo no válido.

Mensajes de validación, localización y accesibilidad

La validación del lado cliente usa ValidationMessage<TValue> para mostrar mensajes para campos individuales y ValidationSummary para mostrar mensajes para todo el formulario, que es la misma manera que la validación interactiva notifica mensajes a los usuarios.

Cuando se configura la localización de validación, los mensajes de error se localizan en el servidor a medida que se representa la página, por lo que la validación del lado cliente muestra las mismas cadenas localizadas que la experiencia del lado servidor. La localización requiere Microsoft.Extensions.Validation. Para obtener más información, consulte Validación en ASP.NET Core.

Los atributos ARIA de los campos de entrada y los contenedores de mensajes de validación los gestiona Blazor automáticamente, por lo que las tecnologías de asistencia anuncian los errores de validación sin necesidad de configuración adicional.

Clases CSS de estado de validación

El motor de validación del lado del cliente aplica las mismas clases CSS que la validación interactiva de Blazor, tal como se muestra en la tabla siguiente.

Elemento Las clases
Input valid o invalid, más modified una vez que el usuario edita el campo
Mensaje de validación validation-message
Resumen de validación validation-summary-errors o validation-summary-valid

La validación del lado cliente también llama a la API de validación de restricciones del explorador, por lo que las pseudo clases :valid CSS estándar y :invalid reflejan el estado de validación actual de cada entrada.

No participar en la validación del lado cliente

La característica se puede deshabilitar en varios niveles. La validación del lado servidor no se ve afectada por cualquiera de las opciones de esta sección.

Darse de baja para un solo formulario

Establezca el parámetro true del componente DataAnnotationsValidator a DisableClientValidation:

<DataAnnotationsValidator DisableClientValidation="true" />

No participar en toda la aplicación

Establezca DisableClientValidation en RazorComponentsServiceOptions cuando los servicios de componentes Razor estén registrados en el archivo Program:

builder.Services.AddRazorComponents(options =>
{
    options.DisableClientValidation = true;
});

La opción global tiene prioridad. Cuando se establece en true, los formularios no emiten reglas de validación del lado cliente.

Excluir un único botón de envío

Use el atributo HTML formnovalidate estándar en el botón. El formulario se publica sin una comprobación del lado cliente y la validación del lado servidor todavía se ejecuta después de la publicación:

<button type="submit" formnovalidate>Save draft</button>

Esto se puede usar para implementar un botón "guardar borrador" o "atrás" que no requiera un formulario completamente válido para que el envío se realice correctamente.

Reglas de validación personalizadas del lado cliente

Los atributos de validación personalizados continúan ejecutándose en el servidor, pero no tienen una implementación del lado cliente de forma predeterminada. La aplicación de una regla personalizada en el explorador implica dos pasos: emitir la regla desde el atributo .NET y registrar un validador de JavaScript coincidente. La implementación del lado servidor sigue siendo autoritativa.

Emisión de la regla desde .NET

Implemente IClientValidationRuleProvider en el atributo de validación y devuelva una o varias ClientValidationRule instancias. La regla Name identifica el validador del lado cliente y Parameters proporciona los valores que necesita el validador.

A continuación, StartsWithAttribute se valida en el servidor en IsValid y aporta una regla del cliente en startswith con un parámetro prefix:

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components.Forms;

namespace BlazorSample.Validation;

// A custom validation attribute that also contributes a client-side rule for static SSR
// forms. The rule name ('startswith') must match the validator registered on the client
// with Blazor.formValidation.addValidator.
public sealed class StartsWithAttribute : ValidationAttribute, IClientValidationRuleProvider
{
    private readonly string prefix;

    public StartsWithAttribute(string prefix)
    {
        this.prefix = prefix;
        ErrorMessage = $"The value must start with '{prefix}'.";
    }

    protected override ValidationResult? IsValid(object? value,
        ValidationContext validationContext)
    {
        // Leave empty values to RequiredAttribute, matching the client-side validator.
        if (value is not string text || text.Length == 0)
        {
            return ValidationResult.Success;
        }

        if (!text.StartsWith(prefix, StringComparison.Ordinal))
        {
            return new ValidationResult(ErrorMessage, [validationContext.MemberName!]);
        }

        return ValidationResult.Success;
    }

    public IEnumerable<ClientValidationRule> GetClientValidationRules()
    {
        yield return new ClientValidationRule(
            "startswith",
            new Dictionary<string, string> { ["prefix"] = prefix });
    }
}

Aplique el atributo al modelo de la manera habitual:

using System.ComponentModel.DataAnnotations;

namespace BlazorSample.Validation;

// Model for the static SSR client-side validation sample. The StartsWith attribute
// contributes a client-side rule enforced in the browser before the form is submitted.
public class ShipModel
{
    [Required]
    [StartsWith("NCC-")]
    public string? Registry { get; set; }
}

Registro del validador de JavaScript

En JavaScript, llame Blazor.formValidation.addValidator(name, validator) a para asociar un nombre de regla a una función de validador. El name debe coincidir exactamente con el ClientValidationRule.Name, incluyendo el uso de mayúsculas y minúsculas. Los registros son para toda la aplicación y el registro del mismo nombre reemplaza de nuevo al validador anterior.

Warning

Si no se registra ningún validador de JavaScript para un nombre de regla emitido, la regla se omite en el explorador. La validación del lado servidor todavía se ejecuta cuando se publica el formulario.

Registre los validadores personalizados una sola vez en el código de inicio de la aplicación. Elija la ubicación de registro en función de cómo Blazor se inicia, como se describe en la tabla siguiente.

Blazor arranque Ubicación del registro
Inicio automático (valor predeterminado) Un script inmediatamente después de blazor.web.js
Manual Blazor.start() Continuación devuelta por Blazor.start()
Cualquier estilo de inicio Devolución de llamada de afterWebStarted un inicializador de JavaScript

Un inicializador de JavaScript funciona con cualquier estilo de inicio. En un archivo denominado {ASSEMBLY NAME}.lib.module.js en la carpeta de wwwroot la aplicación:

// A JavaScript initializer works with automatic or manual Blazor startup. The validation service
// is available when afterWebStarted runs, even if the current page contains no validated form.
export function afterWebStarted(blazor) {
  blazor.formValidation.addValidator('startswith', (context) => {
    const value = context.value;

    // An empty value is valid. Use [Required] to require a value.
    if (!value) {
      return { success: true };
    }

    return { success: value.startsWith(context.params.prefix) };
  });
}

Con el arranque automático, puede cargarse un script de validación específico de la aplicación inmediatamente después de blazor.web.js:

<script src="@Assets["_framework/blazor.web.js"]"></script>
<script src="@Assets["js/custom-validation.js"]"></script>

El segundo script puede llamar Blazor.formValidation.addValidator directamente.

Con el inicio manual, defina el registro en un script de aplicación:

function registerCustomValidators(blazor) {
  blazor.formValidation.addValidator('startswith', (context) => {
    const value = context.value;

    if (!value) {
      return { success: true };
    }

    return { success: value.startsWith(context.params.prefix) };
  });
}

// Automatic startup initializes formValidation before this script runs.
// Manual startup calls registerCustomValidators after Blazor.start completes.
if (Blazor.formValidation) {
  registerCustomValidators(Blazor);
}

Cargue los scripts con el inicio automático deshabilitado y registre los validadores una vez Blazor.start() completado:

<script src="@Assets["_framework/blazor.web.js"]" autostart="false"></script>
<script src="@Assets["js/custom-validation.js"]"></script>
<script>
    Blazor.start().then(() => {
        registerCustomValidators(Blazor);
    });
</script>

Importante

Registre validadores desde el código de inicio de la aplicación, no desde un componente de página o formulario. Un script de componente puede ejecutarse antes de que se inicie Blazor, y los scripts que añade la navegación mejorada no se ejecutan. Los componentes SSR estáticos tampoco pueden usar IJSRuntime porque no tienen un entorno de ejecución interactivo de .NET.

Escritura de funciones de validador de JavaScript

El validador recibe un objeto de contexto con los siguientes miembros, como se muestra en la tabla siguiente.

Miembro Descripción
value El valor actual del campo como una cadena o null/undefined cuando no hay ningún valor.
element Elemento validado input, selecto textarea .
params La regla es Parameters como un diccionario de cadenas.

Se espera que el validador devuelva { success: true } cuando el valor sea válido. Devuelva { success: false } para usar el mensaje proporcionado por el servidor de la regla, o puede devolver { success: false, message: '...' } para anular el mensaje para esa llamada.

Normalmente, los valores vacíos deben considerarse válidos según reglas distintas de required, lo que permite que un campo opcional permanezca vacío y que, aun así, se validen los valores introducidos.

Implemente la misma semántica de regla en .NET y JavaScript, incluida la distinción entre mayúsculas y minúsculas, la normalización y el control de valores vacíos. Si las implementaciones difieren, el explorador y la validación autoritativa del lado servidor pueden generar resultados diferentes.

Validar formulario a petición

La Blazor.formValidation API también expone métodos de JavaScript para validar a petición, como se muestra en la tabla siguiente.

Método Descripción
validateField(element) Valida un único elemento de campo y actualiza su presentación de errores. Devuelve true cuando es válido.
validateForm(form) Valida todos los campos de los que se realiza un seguimiento en un formulario. Devuelve true cuando todos los campos son válidos.

Limitations

  • Las reglas del lado cliente solo se emiten para los campos incluidos en la validación del lado servidor. Sin Microsoft.Extensions.Validation, solo se validan las propiedades del modelo de nivel superior. La validación de objetos y colecciones anidadas requiere que la aplicación llame a AddValidation y que se detecte el modelo. Para obtener más información, consulte Validación en ASP.NET Core. Tenga en cuenta que esta limitación es una característica intencionada para ayudar a evitar errores en los que falta la validación del servidor autoritativo debido a una configuración incorrecta.
  • Las entradas agregadas a un formulario existente mediante una actualización posterior de representación de streaming no reciben validación del lado cliente. Un formulario enviado en un único lote transmitido en flujo se cubre normalmente.
  • Solo los atributos enumerados en Atributos de validación admitidos tienen implementaciones integradas del lado cliente. Por ejemplo, un RangeAttribute con un tipo de operando no numérico solo se aplica en el servidor. Otros atributos requieren una regla de validación personalizada del lado cliente.
  • Los validadores de JavaScript personalizados son sincrónicos. Las reglas que requieren una llamada de red u otro trabajo asincrónico deben ejecutarse en el servidor o usar la validación asincrónica con un modo de representación interactivo. Para obtener más información, consulte ASP.NET Core Blazor validación avanzada de formularios.

Recursos adicionales