Is it possible to toggle Validation Data Annotations on/off in MVC 3?

I have two separate VIEWS accessing the same MODEL. When I put the validator data annotations on the model, it works as advertised and prevents the data from being submitted (for both views) if left blank or not within range. However, I have one view that should be able to allow empty or null values to be saved for a property whereas another view needs to require information to be entered or selected before it lets it through. In other words, I’d like to turn off the validator on the property within the MODEL for one view and leave it on for the other view. Here’s the example code:

MODEL:

[Range(1, 999, ErrorMessage = "A submittal is required")]
public int SubmittalId { get; set; }

VIEW #1:

 <label>@Model.AuditDoc.SubmittalsLabel.ConfigurableLabelDesc</label> @Html.ValidationMessageFor(x => x.AuditDoc.SubmittalId) @Html.DropDownListFor(x => x.AuditDoc.SubmittalId, new SelectList(Model.AuditDoc.ListOfSubmittals, "Id", "Name"))

VIEW #2:

 <label>@Model.AuditDoc.SubmittalsLabel.ConfigurableLabelDesc</label> @Html.DropDownListFor(x => x.AuditDoc.SubmittalId, new SelectList(Model.AuditDoc.ListOfSubmittals, "Id", "Name"))

As you can see, I would like to disable that validator data annotation for View #2 and leave it on for View #1.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

This isn’t possible via the default set of data annotations.. however, you have the choice of using 2 separate view models or writing your own validationAttribute.

I wrote this once.. although I loathed using it..

public class RequiredOnAttribute : ValidationAttribute
{
    public string[] URLs { get; set; }

    public override bool IsValid(object value)
    {
        if (URLs.Contains(System.Web.HttpContext.Current.Request.Url.AbsolutePath))
        {
            if (string.IsNullOrEmpty(value as string))
            {
                return false;
            }
        }
        return true;
    }
}

Usage:

[RequiredOn(URLs = new string[] { "/create", "/edit" })]
public string MyModelField { get; set; }

You could do the same for Range, RegEx, etc..

Method 2

I solved this problem using a different approach.

The trick is not to disable validation per-se, but to clear any inappropriate validation errors before the controller’s action is invoked (so ModelState.IsValid returns true).

If a Model (or ViewModel) object requires custom validation then it implements an interface I defined called ICustomValidation which looks like this:

public interface ICustomValidation {
    void PerformValidation(ModelStateDictionary modelState);
}

My BaseController class (which all of my controllers subclass) has this method override:

protected override void OnActionExecuting(ActionExecutingContext filterContext) {
    base.OnActionExecuting(filterContext);

    // Unfortunately it seems this is the only way to get the Model object
    if( filterContext.ActionParameters.ContainsKey("model") ) {

        Object                    model = filterContext.ActionParameters["model"];
        ModelStateDictionary modelState = filterContext.Controller.ViewData.ModelState; // ViewData.Model always returns null at this point.

        ICustomValidation modelValidation = model as ICustomValidation;
        if( modelValidation != null ) {
            modelValidation.PerformValidation( modelState );
        }
    }

}

So in an example ViewModel class, if I want to disable (or rather: disregard) certain validation errors then it just needs to do this:

public class SomeModel : ICustomValidation {

    [Required]
    public Boolean NamePresent { get; set; }

    [Required]
    public String Name { get; set; }

    public void PerformValidation(ModelStateDictionary modelState) {
        if( !NamePresent ) dict.Remove("Name");
    }
}

In my actual code there’s a bit more logic that clears the ModelStateDictionary in a model-recursive and by-prefix method which keeps it robust.

My solution does not match your problem exactly, but using a similar approach you should be able to get it to work for you.

Method 3

I too would suggest using a different view model object. This article has a nice example of how to implement it cleanly http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

Alternatively, you could simply not call ModelState.IsValid on the controller.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x