tutorial net mvc mantenimiento español datos curso asp c# asp.net-mvc forms validation

c# - mantenimiento - Validación condicional de ASP.NET MVC



mvc asp net (12)

¿Cómo usar las anotaciones de datos para hacer una validación condicional en el modelo?

Por ejemplo, supongamos que tenemos el siguiente modelo (Persona y Senior):

public class Person { [Required(ErrorMessage = "*")] public string Name { get; set; } public bool IsSenior { get; set; } public Senior Senior { get; set; } } public class Senior { [Required(ErrorMessage = "*")]//this should be conditional validation, based on the "IsSenior" value public string Description { get; set; } }

Y la siguiente vista:

<%= Html.EditorFor(m => m.Name)%> <%= Html.ValidationMessageFor(m => m.Name)%> <%= Html.CheckBoxFor(m => m.IsSenior)%> <%= Html.ValidationMessageFor(m => m.IsSenior)%> <%= Html.CheckBoxFor(m => m.Senior.Description)%> <%= Html.ValidationMessageFor(m => m.Senior.Description)%>

Me gustaría ser el campo obligatorio condicional de la propiedad "Senior.Description" basado en la selección de la propiedad "IsSenior" (verdadero -> obligatorio). ¿Cómo implementar la validación condicional en ASP.NET MVC 2 con anotaciones de datos?


Ahora existe un marco que realiza esta validación condicional (entre otras validaciones útiles de anotaciones de datos): http://foolproof.codeplex.com/

Específicamente, eche un vistazo al validador [RequiredIfTrue ("IsSenior")]. Póngalo directamente en la propiedad que desea validar, para que obtenga el comportamiento deseado del error de validación asociado a la propiedad "Senior".

Está disponible como un paquete NuGet.


Ayer tuve el mismo problema pero lo hice de una manera muy limpia que funciona tanto para la validación del lado del cliente como del lado del servidor.

Condición: en función del valor de otra propiedad en el modelo, desea hacer que se requiera otra propiedad. Aquí está el código

public class RequiredIfAttribute : RequiredAttribute { private String PropertyName { get; set; } private Object DesiredValue { get; set; } public RequiredIfAttribute(String propertyName, Object desiredvalue) { PropertyName = propertyName; DesiredValue = desiredvalue; } protected override ValidationResult IsValid(object value, ValidationContext context) { Object instance = context.ObjectInstance; Type type = instance.GetType(); Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null); if (proprtyvalue.ToString() == DesiredValue.ToString()) { ValidationResult result = base.IsValid(value, context); return result; } return ValidationResult.Success; } }

Aquí PropertyName es la propiedad sobre la que desea establecer su condición. DesiredValue es el valor particular de PropertyName (propiedad) para el cual su otra propiedad debe validarse para el requisito.

Digamos que tienes lo siguiente

public class User { public UserType UserType { get; set; } [RequiredIf("UserType", UserType.Admin, ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(ResourceString))] public string Password { get; set; } }

Por último, pero no menos importante, registra el adaptador para tu atributo para que pueda hacer la validación del lado del cliente (lo puse en global.asax, Application_Start)

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),typeof(RequiredAttributeAdapter));


Debe validar a nivel de Persona, no en el nivel Senior, o Senior debe tener una referencia a su Persona padre. Me parece que necesita un mecanismo de autovalidación que defina la validación en la Persona y no en una de sus propiedades. No estoy seguro, pero no creo que DataAnnotations lo admita de inmediato. Lo que puede hacer es crear su propio Attribute que se deriva de ValidationAttribute que se puede decorar en el nivel de clase y luego crear un validador personalizado que también permita que se ejecuten esos validadores de nivel de clase.

Sé que Validation Application Block admite la autovalidación desde el primer momento, pero VAB tiene una curva de aprendizaje bastante empinada. Sin embargo, aquí hay un ejemplo usando VAB:

[HasSelfValidation] public class Person { public string Name { get; set; } public bool IsSenior { get; set; } public Senior Senior { get; set; } [SelfValidation] public void ValidateRange(ValidationResults results) { if (this.IsSenior && this.Senior != null && string.IsNullOrEmpty(this.Senior.Description)) { results.AddResult(new ValidationResult( "A senior description is required", this, "", "", null)); } } }


Estoy usando MVC 5 pero podrías intentar algo como esto:

public DateTime JobStart { get; set; } [AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")] [DisplayName("Start Date")] [Required] public DateTime? StartDate { get; set; }

En su caso, diría algo como "IsSenior == true". Entonces solo necesita verificar la validación en su acción posterior.



He estado usando este sorprendente nuget que hace anotaciones dinámicas ExpressiveAnnotations

Podrías validar cualquier lógica que puedas soñar:

public string Email { get; set; } public string Phone { get; set; } [RequiredIf("Email != null")] [RequiredIf("Phone != null")] [AssertThat("AgreeToContact == true")] public bool? AgreeToContact { get; set; }


Lo he resuelto manejando el diccionario "ModelState" , que contiene el controlador. El diccionario ModelState incluye todos los miembros que deben validarse.

Aquí está la solución:

Si necesita implementar una validación condicional basada en algún campo (p. Ej., Si A = true, se requiere B), mientras mantiene la mensajería de error de nivel de propiedad (esto no es cierto para los validadores personalizados que están a nivel de objeto) puede lograr esto manejando "ModeloEstado", simplemente eliminando validaciones no deseadas de él.

... En alguna clase ...

public bool PropertyThatRequiredAnotherFieldToBeFilled { get; set; } [Required(ErrorMessage = "*")] public string DepentedProperty { get; set; }

... la clase continúa ...

... En alguna acción de controlador ...

if (!PropertyThatRequiredAnotherFieldToBeFilled) { this.ModelState.Remove("DepentedProperty"); }

...

Con esto, logramos la validación condicional, dejando todo lo demás igual.

ACTUALIZAR:

Esta es mi implementación final: he utilizado una interfaz en el modelo y el atributo de acción que valida el modelo que implementa dicha interfaz. Interface prescribe el método Validate (ModelStateDictionary modelState). El atributo de acción solo llama a Validate (modelState) en IValidatorSomething.

No quería complicar esta respuesta, así que no mencioné los detalles finales de implementación (que, al final, importan en el código de producción).



Puede desactivar los validadores de forma condicional eliminando los errores de ModelState:

ModelState["DependentProperty"].Errors.Clear();


Tuve el mismo problema, necesité una modificación del atributo [Requerido] - hacer el campo requerido en dependencia de la solicitud http. La solución fue similar a la respuesta Dan Hunex, pero su solución no funcionó correctamente (ver comentarios). No utilizo una validación discreta, solo MicrosoftMvcValidation.js lista para usar. Aquí está. Implementa tu atributo personalizado:

public class RequiredIfAttribute : RequiredAttribute { public RequiredIfAttribute(/*You can put here pararmeters if You need, as seen in other answers of this topic*/) { } protected override ValidationResult IsValid(object value, ValidationContext context) { //You can put your logic here return ValidationResult.Success;//I don''t need its server-side so it always valid on server but you can do what you need } }

Luego debe implementar su proveedor personalizado para usarlo como un adaptador en su global.asax

public class RequreIfValidator : DataAnnotationsModelValidator <RequiredIfAttribute> { ControllerContext ccontext; public RequreIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) : base(metadata, context, attribute) { ccontext = context;// I need only http request } //override it for custom client-side validation public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { //here you can customize it as you want ModelClientValidationRule rule = new ModelClientValidationRule() { ErrorMessage = ErrorMessage, //and here is what i need on client side - if you want to make field required on client side just make ValidationType "required" ValidationType =(ccontext.HttpContext.Request["extOperation"] == "2") ? "required" : "none"; }; return new ModelClientValidationRule[] { rule }; } }

Y modifique su global.asax con una línea

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequreIfValidator));

Y aquí está

[RequiredIf] public string NomenclatureId { get; set; }

La principal ventaja para mí es que no tengo que codificar el validador de cliente personalizado como en el caso de una validación discreta. funciona igual que [Obligatorio], pero solo en los casos que desee.


Uso típico para la eliminación condicional de errores del estado del modelo:

  1. Hacer la primera parte condicional de la acción del controlador
  2. Realice la lógica para eliminar el error de ModelState
  3. Haga el resto de la lógica existente (típicamente validación del estado del modelo, luego todo lo demás)

Ejemplo:

public ActionResult MyAction(MyViewModel vm) { // perform conditional test // if true, then remove from ModelState (e.g. ModelState.Remove("MyKey") // Do typical model state validation, inside following if: // if (!ModelState.IsValid) // Do rest of logic (e.g. fetching, saving

En su ejemplo, guarde todo tal como está y agregue la lógica sugerida a la Acción de su controlador. Supongo que su ViewModel transferido a la acción del controlador tiene los objetos Person y Senior Person con datos poblados en ellos desde la UI.


hay una manera mucho mejor de agregar reglas de validación condicionales en MVC3. Haga que su modelo herede IValidatableObject e implemente el método Validate:

public class Person : IValidatableObject { public string Name { get; set; } public bool IsSenior { get; set; } public Senior Senior { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (IsSenior && string.IsNullOrEmpty(Senior.Description)) yield return new ValidationResult("Description must be supplied."); } }

vea más de una descripción en http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx