Disable Required validation attribute under certain circumstances
Asked Answered
L

17

148

I was wondering if it is possible to disable the Required validation attribute in certain controller actions. I am wondering this because on one of my edit forms I do not require the user to enter values for fields that they have already specified previously. However I then implement logic that when they enter a value it uses some special logic to update the model, such as hashing a value etc.

Any sugestions on how to get around this problem?

EDIT:
And yes client validation is a problem here to, as it will not allow them to submit the form without entering a value.

Leomaleon answered 20/3, 2011 at 7:34 Comment(5)
+1 good Q. Would be good to mention client validation here. One option is to remove the RequiredAttr completely and do a server side check when you need to. But this would be tricky on the clientCondensed
Points for anyone who also covers disabling certain fields from client validation (no removing the references to jquery validation)Condensed
Maybe i'm missing your point, but if the user has already specified the values beforehand, then those values are already present, and thus will pass Required validation. Did you mean something else?Winou
Because these values have since been hashed, such as password and security answer, so if they enter a new value on the edit form I want to re-hash the new value before insertion, but i also want the option for it to be left blank sort of thing.Territoriality
@gideon: see Adrian Smith's answer: https://mcmap.net/q/157781/-disable-required-validation-attribute-under-certain-circumstancesPyaemia
B
80

This problem can be easily solved by using view models. View models are classes that are specifically tailored to the needs of a given view. So for example in your case you could have the following view models:

public UpdateViewView
{
    [Required]
    public string Id { get; set; }

    ... some other properties
}

public class InsertViewModel
{
    public string Id { get; set; }

    ... some other properties
}

which will be used in their corresponding controller actions:

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

[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
    ...
}
Burrow answered 20/3, 2011 at 9:59 Comment(7)
Not always true if you have a boolean/bit that is not nullable. But really doesn't make a difference since its going to end up true or false. I had css to highlight required fields and it falsely highlighted the CheckBoxFor item. My solution: $("#IsValueTrue").removeAttr("data-val-required");Ciapas
In update we generally have (FormCollection collection). could you please explain how you are using model as parameterJeana
No, we don't usually have Update(FormCollection collection), at least I never do. I always define and use a specific view model: Update(UpdateViewView model).Burrow
Overloading methods with the same HTTP action are not allowed, so to me it seems like this would not work. Am I missing something?Tambour
@edgi, no, you are not missing anything. It's a mistake in my post. The second action method should obviously be called Insert. Thanks for pointing this out.Burrow
I'm using ViewModels, but my VM inherits a base class that has a Title property attributed as Required, is there a way to disable that in the subclass?Aboveground
HI @DarinDimitrov, I Jus wanted to know, in case of complex models (as in MVC 5 ) with inheritance and dropdownList initializations before making a Get request.. what would be the best approach, for insert, update validation actions.. ..Separate Views?? or .. Thnx (Irfan)Dariusdarjeeling
H
57

If you just want to disable validation for a single field in client side then you can override the validation attributes as follows:

@Html.TextBoxFor(model => model.SomeValue, 
                new Dictionary<string, object> { { "data-val", false }})
Harmaning answered 20/3, 2012 at 3:42 Comment(7)
What worked for me via jQuery: $("#SomeValue").removeAttr("data-val-required");Ciapas
I like this approach but I needed to re-parse the form validation attributes using: $('form').removeData('unobtrusiveValidation'); $('form').removeData('validator'); $.validator.unobtrusive.parse('selector for your form');Hamm
@Html.TexBoxFor(model => model.SomeValue, new { data_val = false }) - easier to read IMO.Linn
I liked most of this approach to leave me give a fine control of each field, but you could add to cancel ModelState.IsValid when send data to save by POST. Maybe cause some risk ?Frenchy
If you want to disable it through jQuery: $(".search select").attr('data-val', false);Pyaemia
IT removes all the validation,is it possible to remove only required field validation without javascriptPhyllotaxis
@NayanaSetty try overriding the individual validation attributes: @Html.TexBoxFor(model => model.SomeValue, new { "data-val-required" = false }).Photoelasticity
S
46

I know this question has been answered a long time ago and the accepted answer will actually do the work. But there's one thing that bothers me: having to copy 2 models only to disable a validation.

Here's my suggestion:

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; }
    }
}

This way, you don't have to bother with client/server side validations, the framework will behave the way it's supposed to. Also, if you define a [Display] attribute on the base class, you don't have to redefine it in your UpdateModel.

And you can still use these classes the same way:

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

[HttpPost]
public ActionResult Insert(InsertModel model)
{
    ...
}
Shaunta answered 19/9, 2013 at 14:56 Comment(8)
I like this approach better, especially if you have a long list of validation attributes. In your example, you can add more attributes in the base class to have the benefit more apparent. The only disadvantage I can see is that there is no way for inheriting properties to override the attributes. Example, if you have a [Required] property on the base class, the inheriting property is forced to be [Required] also, unless you have a custom [Optional] attribute.Rule
I thought of something like this too, although I have a viewModel that has an object 'Project' that has multiple attributes and i only want one of these attributes validated under certain circumstances. I dont think i can just override a attribute of an object right? any advice?Groceryman
You can't override the attribute. The base class should only contain common attributes for all sub classes. Then, your sub classes should define the attributes they need.Shaunta
Most elegant, reusable, clear solution. Replications are bad. Polymorphism is the way. +1Petrify
in my case a base class has a required attribute and I want to make it non required in my parent class. Is it possible without having two copies of model?Maher
Which model would you now use to create the database for EF? would you create another model?Tinge
@Tinge Depends. The object structure exposed by your Web API doesn't necessarily suits your needs at the database level. If it does, you'd probably use the UpdateModel for the IDproperty. Otherwise, I'd create another object to properly fit what you need in the database and convert the UpdateModel into this new object (we use AutoMapper for that).Shaunta
In my case, I want [Required] on the InsertModel but not on UpdateModel. So I created a base class ModelBase with no required attributes. InsertModel is derived off of ModelBase and has override properties that also have [Required] attribute. UpdateModel is derived off ModelBase and doesn't have to override anything. Works well for me!Sabelle
D
40

You can remove all validation off a property with the following in your controller action.

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

@Ian's comment regarding MVC5

The following is still possible

ModelState.Remove("PropertyNameInModel");

Bit annoying that you lose the static typing with the updated API. You could achieve something similar to the old way by creating an instance of HTML helper and using NameExtensions Methods.

Dreg answered 9/4, 2015 at 13:31 Comment(3)
Except... there isn't a method on ModelState that matches that signature. Not in MVC 5, at least.Baby
The question wasn't how to remove all validation. It was how to remove required field validation. You might want to do this while leaving other validation rules in place.Bodoni
This is indeed the best solution and what worked for me even in .net core thank you @Dreg ModelState.Remove("PropertyNameInModel");Colicroot
T
18

Client side For disabling validation for a form, multiple options based on my research is given below. One of them would would hopefully work for you.

Option 1

I prefer this, and this works perfectly for me.

(function ($) {
    $.fn.turnOffValidation = function (form) {
        var settings = form.validate().settings;

        for (var ruleIndex in settings.rules) {
            delete settings.rules[ruleIndex];
        }
    };
})(jQuery); 

and invoking it like

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

Option 2

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

Option 3

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

Option 4

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

Option 5

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

Server Side

Create an attribute and mark your action method with that attribute. Customize this to adapt to your specific needs.

[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();
        }
    }
}

A better approach has been described here Enable/Disable mvc server side validation dynamically

Tonsure answered 12/6, 2013 at 14:21 Comment(2)
$('input selector').each(function () { $(this).rules('remove');}); helped meNervous
The question was specifically about removing required field validation, not about removing all validation. Your answer is about removing all validation.Bodoni
N
14

Personally I would tend to use the approach Darin Dimitrov showed in his solution. This frees you up to be able to use the data annotation approach with validation AND have separate data attributes on each ViewModel corresponding to the task at hand. To minimize the amount of work for copying between model and viewmodel you should look at AutoMapper or ValueInjecter. Both have their individual strong points, so check them both.

Another possible approach for you would be to derive your viewmodel or model from IValidatableObject. This gives you the option to implement a function Validate. In validate you can return either a List of ValidationResult elements or issue a yield return for each problem you detect in validation.

The ValidationResult consists of an error message and a list of strings with the fieldnames. The error messages will be shown at a location near the input field(s).

public IEnumerable<ValidationResult> 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;
}
Navigable answered 20/3, 2011 at 15:8 Comment(2)
can we hook this on client side?Annamarieannamese
client-side validation generally is done for individual fields only, performing interactive, field-by-field validation feedback, as a convenience to the user. Since the object-validation step generally involves dependent validation (multiple fields and/or conditions that are external to the object itself) this can't necessarily be performed on the client-side, even if you could compile the code to JavaScript. If complex/dependent validation on the client-side does add value in your case, you will need to use the onsubmit-callback and duplicate the validation logic on the client-side.Overtax
C
9

The cleanest way here I believe is going to disable your client side validation and on the server side you will need to:

  1. ModelState["SomeField"].Errors.Clear (in your controller or create an action filter to remove errors before the controller code is executed)
  2. Add ModelState.AddModelError from your controller code when you detect a violation of your detected issues.

Seems even a custom view model here wont solve the problem because the number of those 'pre answered' fields could vary. If they dont then a custom view model may indeed be the easiest way, but using the above technique you can get around your validations issues.

Cleveland answered 21/3, 2011 at 5:6 Comment(1)
This is just what I needed. I had one view and differente actions occur in this view, so I couldn't make it with differente ViewModels. This works like a charmQueeniequeenly
L
7

this was someone else's answer in the comments...but it should be a real answer:

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

tested on MVC 6 with a field having the [Required] attribute

answer stolen from https://stackoverflow.com/users/73382/rob above

Llama answered 10/4, 2015 at 20:15 Comment(5)
What about server side validation?Petrify
ModelState.Remove, right? At any rate, for me, the issue was that I had a second entity being included in my model...the primary I wanted validation on, but the secondary didn't need validation on that page...so, under this scenario, only the JQuery was necessary.Llama
I think that the link is broken, so please edit. This is a partial answerPetrify
It's weird that you say this works in MVC6 (I don't have option to test on MVC6 currently) but does not work for me on MVC4 which I am currently using.Electrolysis
The question is for MVC/C# - not JS, the answer would not work server sideFic
F
2

I was having this problem when I creating a Edit View for my Model and I want to update just one field.

My solution for a simplest way is put the two field using :

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

Comments is the field that I only update in Edit View, that not have Required Attribute.

ASP.NET MVC 3 Entity

Frenchy answered 1/8, 2012 at 15:39 Comment(0)
M
1

AFAIK you can not remove attribute at runtime, but only change their values (ie: readonly true/false) look here for something similar . As another way of doing what you want without messing with attributes I will go with a ViewModel for your specific action so you can insert all the logic without breaking the logic needed by other controllers. If you try to obtain some sort of wizard (a multi steps form) you can instead serialize the already compiled fields and with TempData bring them along your steps. (for help in serialize deserialize you can use MVC futures)

Manheim answered 20/3, 2011 at 7:44 Comment(0)
S
1

What @Darin said is what I would recommend as well. However I would add to it (and in response to one of the comments) that you can in fact also use this method for primitive types like bit, bool, even structures like Guid by simply making them nullable. Once you do this, the Required attribute functions as expected.

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
}
Sofar answered 12/6, 2013 at 14:40 Comment(0)
A
1

As of MVC 5 this can be easily achieved by adding this in your global.asax.

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Acceptor answered 8/1, 2018 at 11:25 Comment(0)
C
1

I was looking for a solution where I can use the same model for an insert and update in web api. In my situation is this always a body content. The [Requiered] attributes must be skipped if it is an update method. In my solution, you place an attribute [IgnoreRequiredValidations] above the method. This is as follows:

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

    [HttpPut]
    [IgnoreRequiredValidations]
    public IHttpActionResult Update(SameModel model)
    {
        ...
    }

    ...

What else needs to be done? An own BodyModelValidator must becreated and added at the startup. This is in the HttpConfiguration and looks like this: 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());
        }

        ...

My own BodyModelValidator is derived from the DefaultBodyModelValidator. And i figure out that i had to override the 'ShallowValidate' methode. In this override i filter the requierd model validators. And now the IgnoreRequiredOrDefaultBodyModelValidator class and the IgnoreRequiredValidations attributte class:

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<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache;

        static IgnoreRequiredOrDefaultBodyModelValidator()
        {
            _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>();
        }

        protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> 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<IgnoreRequiredValidationsAttribute>(false) != null;
        } 
        #endregion
    }

    [AttributeUsage(AttributeTargets.Method, Inherited = true)]
    public class IgnoreRequiredValidationsAttribute : Attribute
    {

    }
}

Sources:

Correlation answered 30/7, 2018 at 8:51 Comment(0)
S
0

If you don't want to use another ViewModel you can disable client validations on the view and also remove the validations on the server for those properties you want to ignore. Please check this answer for a deeper explanation https://mcmap.net/q/160666/-disable-required-validation-specific-field-in-the-view-asp-net-mvc-4

Shephard answered 6/3, 2013 at 13:40 Comment(0)
M
0

In my case the same Model was used in many pages for re-usability purposes. So what i did was i have created a custom attribute which checks for exclusions

public class ValidateAttribute : ActionFilterAttribute
{
    public string Exclude { get; set; }
    public string Base { get; set; }
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!string.IsNullOrWhiteSpace(this.Exclude))
        {
            string[] excludes = this.Exclude.Split(',');
            foreach (var exclude in excludes)
            {
                actionContext.ModelState.Remove(Base + "." + exclude);
            }
        }
        if (actionContext.ModelState.IsValid == false)
        {
            var mediaType = new MediaTypeHeaderValue("application/json");
            var error = actionContext.ModelState;

            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType);

        }
    }
}

and in your controller

[Validate(Base= "person",Exclude ="Age,Name")]
    public async Task<IHttpActionResult> Save(User person)
    {

            //do something           

    }

Say the Model is

public class User
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Range(18,99)]
    public string Age { get; set; }
    [MaxLength(250)]
    public string Address { get; set; }
}
Monohydroxy answered 31/5, 2019 at 12:55 Comment(0)
C
0

This one worked for me:

$('#fieldId').rules('remove', 'required');
Carin answered 11/2, 2022 at 19:8 Comment(0)
S
-1

Yes it is possible to disable Required Attribute. Create your own custom class attribute (sample code called ChangeableRequired) to extent from RequiredAtribute and add a Disabled Property and override the IsValid method to check if it is disbaled. Use reflection to set the disabled poperty, like so:

Custom Attribute:

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);
       }
    }
}

Update you property to use your new custom Attribute:

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

where you need to disable the property use reflection to set it:

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;

This feels nice and clean?

NB: The validation above will be disabled while your object instance is alive\active...

Senility answered 15/3, 2016 at 13:59 Comment(2)
After a few debates on this I would like to mention that I don't recommend disabling validation but rather review the rule. If you disable it, you creating a dependency to re-enable the rule and I would suggest review the rule.Senility
Changing a static value to completely disable all validation of that field executed within that same process sounds like a terrible idea.Blayze

© 2022 - 2024 — McMap. All rights reserved.