Inhabilite el atributo de validación requerido bajo ciertas circunstancias

Me preguntaba si es posible desactivar el atributo de validación requerida en ciertas acciones del controlador. Me pregunto esto porque en uno de mis formularios de edición no es necesario que el usuario ingrese valores para los campos que ya han especificado previamente. Sin embargo, luego implemento la lógica que cuando ingresan un valor usa alguna lógica especial para actualizar el modelo, como hash, un valor, etc.

¿Alguna sugerencia sobre cómo solucionar este problema?

EDITAR:
Y sí, la validación del cliente es un problema aquí, ya que no les permitirá enviar el formulario sin ingresar un valor.

Este problema se puede resolver fácilmente mediante el uso de modelos de vista. Los modelos de vista son clases que se adaptan específicamente a las necesidades de una vista determinada. Entonces, por ejemplo, en su caso podría tener los siguientes modelos de vista:

 public UpdateViewView { [Required] public string Id { get; set; } ... some other properties } public class InsertViewModel { public string Id { get; set; } ... some other properties } 

que se usará en sus acciones de controlador correspondientes:

 [HttpPost] public ActionResult Update(UpdateViewView model) { ... } [HttpPost] public ActionResult Insert(InsertViewModel model) { ... } 

Si solo desea deshabilitar la validación de un solo campo en el lado del cliente, puede anular los atributos de validación de la siguiente manera:

 @Html.TexBoxFor(model => model.SomeValue, new Dictionary { { "data-val", false }}) 

Sé que esta pregunta ha sido respondida hace mucho tiempo y la respuesta aceptada realmente hará el trabajo. Pero hay una cosa que me molesta: tener que copiar 2 modelos solo para deshabilitar una validación.

Aquí está mi sugerencia:

 public class InsertModel { [Display(...)] public virtual string ID { get; set; } ...Other properties } public class UpdateModel : InsertModel { [Required] public override string ID { get { return base.ID; } set { base.ID = value; } } } 

De esta forma, no tiene que preocuparse por las validaciones del cliente / servidor, el marco se comportará de la manera que se supone. Además, si defines un atributo [Display] en la clase base, no tienes que redefinirlo en tu UpdateModel .

Y aún puedes usar estas clases de la misma manera:

 [HttpPost] public ActionResult Update(UpdateModel model) { ... } [HttpPost] public ActionResult Insert(InsertModel model) { ... } 

Personalmente, tendería a utilizar el enfoque que Darin Dimitrov mostró en su solución. Esto lo libera para poder utilizar el enfoque de anotación de datos con validación Y tiene atributos de datos separados en cada modelo de vista correspondiente a la tarea en cuestión. Para minimizar la cantidad de trabajo para copiar entre el modelo y el modelo de vista, debe mirar AutoMapper o ValueInjecter . Ambos tienen sus puntos fuertes individuales, así que revíselos a los dos.

Otro enfoque posible para usted sería derivar su modelo de vista o modelo de IValidatableObject. Esto le da la opción de implementar una función Validar. En la validación, puede devolver una Lista de elementos de ValidationResult o emitir un retorno de rendimiento por cada problema que detecte en la validación.

El ValidationResult consiste en un mensaje de error y una lista de cadenas con los nombres de campo. Los mensajes de error se mostrarán en una ubicación cercana a los campos de entrada.

 public IEnumerable Validate(ValidationContext validationContext) { if( NumberField < 0 ) { yield return new ValidationResult( "Don't input a negative number", new[] { "NumberField" } ); } if( NumberField > 100 ) { yield return new ValidationResult( "Don't input a number > 100", new[] { "NumberField" } ); } yield break; } 

Lado del cliente Para deshabilitar la validación de un formulario, a continuación se presentan varias opciones basadas en mi investigación. Uno de ellos con suerte trabajaría para ti.

Opción 1

Prefiero esto, y esto funciona perfectamente para mí.

 (function ($) { $.fn.turnOffValidation = function (form) { var settings = form.validate().settings; for (var ruleIndex in settings.rules) { delete settings.rules[ruleIndex]; } }; })(jQuery); 

e invocándolo como

 $('#btn').click(function () { $(this).turnOffValidation(jQuery('#myForm')); }); 

opcion 2

 $('your selector here').data('val', false); $("form").removeData("validator"); $("form").removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse("form"); 

Opción 3

 var settings = $.data($('#myForm').get(0), 'validator').settings; settings.ignore = ".input"; 

Opción 4

  $("form").get(0).submit(); jQuery('#createForm').unbind('submit').submit(); 

Opción 5

 $('input selector').each(function () { $(this).rules('remove'); }); 

Lado del servidor

Crea un atributo y marca tu método de acción con ese atributo. Personalícelo para adaptarlo a sus necesidades específicas.

 [AttributeUsage(AttributeTargets.All)] public class IgnoreValidationAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var modelState = filterContext.Controller.ViewData.ModelState; foreach (var modelValue in modelState.Values) { modelValue.Errors.Clear(); } } } 

Se ha descrito un mejor enfoque aquí. Habilite / deshabilite la validación del lado del servidor mvc dinámicamente.

Puede eliminar toda la validación de una propiedad con lo siguiente en su acción de controlador.

 ModelState.Remove(x => x.SomeProperty); 

@ Comentario de Ian sobre MVC5

Lo siguiente sigue siendo posible

 ModelState.Remove("PropertyNameInModel"); 

Es un poco molesto que pierdas el tipado estático con la API actualizada. Podrías lograr algo similar a la forma anterior creando una instancia de HTML helper y usando los métodos NameExtensions .

La forma más limpia aquí creo que va a deshabilitar su validación del lado del cliente y en el lado del servidor deberá:

  1. ModelState [“SomeField”]. Errors.Clear (en su controlador o crear un filtro de acción para eliminar errores antes de que se ejecute el código del controlador)
  2. Agregue ModelState.AddModelError desde su código de controlador cuando detecte una violación de sus problemas detectados.

Parece que incluso un modelo de vista personalizado aquí no resolverá el problema porque la cantidad de esos campos “pre-respondidos” podría variar. Si no lo hacen, entonces un modelo de vista personalizada puede ser la manera más fácil, pero utilizando la técnica anterior puede solucionar sus problemas de validación.

esta fue la respuesta de otra persona en los comentarios … pero debería ser una respuesta real:

$("#SomeValue").removeAttr("data-val-required")

probado en MVC 6 con un campo que tiene el atributo [Required]

respuesta robada de https://stackoverflow.com/users/73382/rob arriba

Estaba teniendo este problema cuando creo una vista de edición para mi modelo y quiero actualizar solo un campo.

Mi solución de la manera más simple es poner los dos campos usando:

  <%: Html.HiddenFor(model => model.ID) %> <%: Html.HiddenFor(model => model.Name)%> <%: Html.HiddenFor(model => model.Content)%> <%: Html.TextAreaFor(model => model.Comments)%> 

Comentarios es el campo que solo actualizo en Editar Vista, que no tiene Atributo Requerido.

Entidad ASP.NET MVC 3

AFAIK no se puede eliminar el atributo en tiempo de ejecución, pero solo cambiar sus valores (es decir, solo lectura / false) busque aquí algo similar . Como otra forma de hacer lo que quiere sin interferir con los atributos, iré con un ViewModel para su acción específica para que pueda insertar toda la lógica sin romper la lógica que necesitan otros controladores. Si intenta obtener algún tipo de asistente (un formulario de varios pasos), en su lugar puede serializar los campos ya comstackdos y, con TempData, haga que sigan sus pasos. (para ayuda en serializar deserializar puede usar futuros de MVC )

Lo que dijo @Darin es lo que recomendaría también. Sin embargo, le agregaría (y en respuesta a uno de los comentarios) que de hecho también puede usar este método para tipos primitivos como bit, bool, incluso estructuras como Guid simplemente haciendo que se puedan agregar nulos. Una vez que hace esto, el atributo Required funciona como se espera.

 public UpdateViewView { [Required] public Guid? Id { get; set; } [Required] public string Name { get; set; } [Required] public int? Age { get; set; } [Required] public bool? IsApproved { get; set; } //... some other properties } 

A partir de MVC 5 esto se puede lograr fácilmente agregando esto en su global.asax .

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 

Estaba buscando una solución donde pueda usar el mismo modelo para insertar y actualizar en la API web. En mi situación, esto es siempre un contenido corporal. Los atributos [Requiered] deben omitir si se trata de un método de actualización. En mi solución, [IgnoreRequiredValidations] un atributo [IgnoreRequiredValidations] sobre el método. Esto es como sigue:

 public class WebServiceController : ApiController { [HttpPost] public IHttpActionResult Insert(SameModel model) { ... } [HttpPut] [IgnoreRequiredValidations] public IHttpActionResult Update(SameModel model) { ... } ... 

¿Qué más hay que hacer? Un propio BodyModelValidator se debe crear y agregar al inicio. Esto está en HttpConfiguration y se ve así: config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());

 using Owin; using your_namespace.Web.Http.Validation; [assembly: OwinStartup(typeof(your_namespace.Startup))] namespace your_namespace { public class Startup { public void Configuration(IAppBuilder app) { Configuration(app, new HttpConfiguration()); } public void Configuration(IAppBuilder app, HttpConfiguration config) { config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator()); } ... 

Mi propio BodyModelValidator se deriva de DefaultBodyModelValidator. Y descubro que tuve que anular el método ‘ShallowValidate’. En esta anulación, filtro los validadores de modelo requeridos. Y ahora la clase IgnoreRequiredOrDefaultBodyModelValidator y la clase de atribución IgnoreRequiredValidations:

 using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web.Http.Controllers; using System.Web.Http.Metadata; using System.Web.Http.Validation; namespace your_namespace.Web.Http.Validation { public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator { private static ConcurrentDictionary _ignoreRequiredValidationByActionBindingCache; static IgnoreRequiredOrDefaultBodyModelValidator() { _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary(); } protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable validators) { var actionContext = validationContext.ActionContext; if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding)) validators = validators.Where(v => !v.IsRequired); return base.ShallowValidate(metadata, validationContext, container, validators); } #region RequiredValidationsIsIgnored private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding) { bool ignore; if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore)) _ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor)); return ignore; } private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor) { if (actionDescriptor == null) return false; return actionDescriptor.MethodInfo.GetCustomAttribute(false) != null; } #endregion } [AttributeUsage(AttributeTargets.Method, Inherited = true)] public class IgnoreRequiredValidationsAttribute : Attribute { } } 

Fuentes:

Si no desea utilizar otro ViewModel, puede deshabilitar las validaciones del cliente en la vista y también eliminar las validaciones en el servidor para aquellas propiedades que desea ignorar. Consulte esta respuesta para obtener una explicación más detallada https://stackoverflow.com/a/15248790/1128216

Sí, es posible desactivar el atributo obligatorio. Cree su propio atributo de clase personalizado (código de ejemplo llamado ChangeableRequired) para extender desde RequiredAtribute y agregue una propiedad deshabilitada y anule el método IsValid para comprobar si está desactivada. Utilice la reflexión para establecer la propiedad de los discapacitados, de esta manera:

Atributo personalizado:

 namespace System.ComponentModel.DataAnnotations { public class ChangeableRequired : RequiredAttribute { public bool Disabled { get; set; } public override bool IsValid(object value) { if (Disabled) { return true; } return base.IsValid(value); } } } 

Actualice su propiedad para usar su nuevo atributo personalizado:

  class Forex { .... [ChangeableRequired] public decimal? ExchangeRate {get;set;} .... } 

donde necesita deshabilitar la propiedad use reflection para establecerlo:

 Forex forex = new Forex(); // Get Property Descriptor from instance with the Property name PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"]; //Search for Attribute ChangeableRequired attrib = (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)]; // Set Attribute to true to Disable attrib.Disabled = true; 

Esto se siente agradable y limpio?

NB: la validación anterior se deshabilitará mientras su instancia de objeto esté activa \ active …

    Intereting Posts