c# - validationmessage - validation summary asp net mvc 4
¿Hay alguna forma de ignorar algunas propiedades(en un POCO) al validar un formulario en ASP.NET MVC3? (8)
¿Qué pasa con la clase personalizada IgnoreModelErrors?
http://mrbigglesworth79.blogspot.in/2011/12/partial-validation-with-data.html
Herede de la clase ActionFilterAttribute y borra los errores [según los nombres coincidentes o los patrones de expresiones regulares] en OnActionExecuting como se muestra en el enlace anterior. Esto será más limpio.
Tengo un asistente de registro para el registro de nuevos usuarios. Cuando trato de ir a la segunda página, recibo errores de validación porque mi objeto de User
aún no se ha completado. ¿Hay alguna forma en que pueda decirle a cada ActionMethod
que ignore algunas propiedades cuando comprueba las comprobaciones ModelState.IsValid
?
p.ej. (Simplificado, código pseduo)
public class User
{
[Required]
public string Name; // Asked on page 1.
[Required]
public int Age; // Asked on page 1.
[Required]
public string Avatar; // Asked on Page 2.
}
se queja diciendo que el Avatar es requerido / no puede ser nulo. Pero no tengo la oportunidad de pedirle al usuario que complete esto, hasta la página siguiente.
¿Es posible pedir ignorar esta comprobación, en la página 1?
En la acción, simplemente elimine los errores de los elementos que aún no se han verificado. Esto hace que su modelo sea válido para los artículos ya comprobados.
foreach (var error in ModelState["Avatar"].Errors)
{
ModelState["Avatar"].Errors.Remove(error);
}
o
ModelState["Avatar"].Errors.Clear();
Estaba jugando con los formularios de validación y ModelState
y descubrí una solución muy fácil para su problema sin escribir ningún método nuevo, anulaciones, etc.
ModelState.Where(m => m.Key == "Avatar").FirstOrDefault().Value.Errors.Clear();
// At this point ModeState will have an error for that Key,
// by applying Clear it remove the error so modelstate becomes valid again
if (!ModelState.IsValid) {
return View("User", model);
} else {
try {
// do something
} catch {
TempData["errorMessage"] = "something went wrong";
}
}
Esto se discute en el libro asp.net mvc 2 de Steve Sanderson, página 486.
Cree un atributo personalizado, ValidateIncomingValuesOnlyAttribute, que hereda de ActionFilterAttribute, y aplíquelo a su clase de controlador.
Reemplace el método OnActionExecuting:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
var incomingValues = filterContext.Controller.ValueProvider;
var keys = modelState.Keys.Where(x => !incomingValues.ContainsPrefix(x));
foreach(var key in keys)
{
modelState[key].Errors.Clear();
}
}
De esa forma, validará los datos correspondientes a cada paso en el asistente solamente. Entonces necesita una página de confirmación sin ingreso de datos para enviar los datos validados al servidor.
Pero sobre todo, lea el libro de Steve Sanderson, le da una solución funcional a este y su otro problema.
Apéndice:
Si en lugar de lo anterior decide mapear a un modelo de vista, tenga cuidado porque tendrá que:
a. No decorar las propiedades de viewmodel con atributos de anotación de datos de validación, en cuyo caso solo se validará una vez que el usuario haya completado el asistente completo e intente enviarlo a la base de datos. Esto sería muy naff desde la perspectiva del usuario ...
segundo. De lo contrario, todavía tiene que usar la técnica descrita por S Sanderson, es decir, eliminar cualquier error de validación que no pertenezca a los campos en el paso actual.
No veo que la respuesta aceptada responda a la pregunta como se hizo.
Para ignorar las propiedades de ModelState, aquí está el código más simple.
if (ModelState["PropertyName"] != null) ModelState["PropertyName"].Errors.Clear();
Puede usar el atributo de enlace para esto: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/
Una mejor opción sería usar ViewModels.
Tenía una entidad de referencia que no debía ser validada.
Se eliminó de la validación al comienzo de la acción:
[HttpPost]
public async Task<IActionResult> Post([FromBody] Contact contact)
{
var skipped = ModelState.Keys.Where(key => key.StartsWith(nameof(Contact.Portfolios)));
foreach (var key in skipped)
ModelState.Remove(key);
//ModelState doesn''t include anything about Portfolios which we''re not concerned with
if (!ModelState.IsValid)
return BadRequest(ModelState);
//Rest of action
}
ViewModels que coinciden exactamente con los datos que se están devolviendo es generalmente la técnica recomendada, ya que es muy predecible y obtiene todos los beneficios de tipificación fuerte, andamios, etc. Por otra parte, el uso de BindAttribute puede requerir que tome las propiedades que son no se vuelve a publicar en la cuenta, y puede resultar en un fallo silencioso en el tiempo de ejecución cuando se cambia el nombre de una propiedad, pero las cadenas BindAttribute Include o Exclude no lo son. Evitar el uso de atributos de validación tiene muchos inconvenientes en MVC y debería reemplazarse con alguna otra técnica de validación como IValidatableObject o FluentValidation.
A pesar de todos los beneficios de ViewModels y las advertencias que acompañan a BindAttribute, a veces puede ser preferible usar BindAttribute y publicar parcialmente en un modelo / viewmodel. Este ActionFilterAttribute cubre ese caso exacto. Toma el código @awrigley citado un paso más allá, pero en lugar de eliminar los errores basados en el ValueProvider, borra los errores basados en el uso del atributo BindAttribute (por ejemplo, Incluir y Excluir). Este atributo se puede agregar de forma segura a GlobalFilterCollection porque no cambiará el comportamiento de la validación de MVC cuando no se haya aplicado el atributo BindAttribute. Tenga en cuenta: no he hecho un uso intensivo de esto, pero funciona bien para mis casos básicos.
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
/// <summary>
/// When the BindAttribute is in use, validation errors only show for values that
/// are included or not excluded.
/// </summary>
public class ValidateBindableValuesOnlyAttributes : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
var includedProperties = filterContext.ActionDescriptor.GetParameters()
.SelectMany(o => o.BindingInfo.Include.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));
var excludedProperties = filterContext.ActionDescriptor.GetParameters()
.SelectMany(o => o.BindingInfo.Exclude.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));
var ignoreTheseProperties = new List<KeyValuePair<string, ModelState>>();
if (includedProperties.Any())
{
ignoreTheseProperties.AddRange(modelState.Where(k => !includedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(/.|/[|$)"))));
}
ignoreTheseProperties.AddRange(modelState.Where(k => excludedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(/.|/[|$)"))));
foreach (var item in ignoreTheseProperties)
{
item.Value.Errors.Clear();
}
}
}