0

I have a partial view that displays a number of inputs based on a view model. In some situations, some of those inputs are not rendered by the partial view, but are still decorated with [Required] attributes in the view model. As a result, when the form is posted back to my controller, ModelState.IsValid returns false. Is there a way to bypass this?

Mykroft
  • 13,077
  • 13
  • 44
  • 72
  • 1
    I would say that you should change your view models, but it's hard to say without knowing the situation. You can manually "remove errors from ModelState", see : http://stackoverflow.com/questions/14008561/is-there-a-strongly-named-way-to-remove-modelstate-errors-in-asp-net-mvc – Raphaël Althaus May 22 '14 at 19:06
  • When the post content is bound to the view model, it does not matter if the source of a field is a input[type=hidden] or input[type=text]. If there is a value it will be bound, otherwise not. And after that the model validation will occur. – gustavodidomenico May 22 '14 at 19:07
  • mvc is not validationg the filed, it is validating the class. so if you class has a required attribute and you are posting a 'x' class it wont be valid, you have to remove that manually or create another class that has no required fileds – bto.rdz May 22 '14 at 19:11

4 Answers4

1

I'd recommend separating your validation from your base model.

public class MyModel
{
  public string MyString { get; set; }
  public string MyHiddenField { get; set; }
}

public interface IMyModel_ValidateMystringOnly
{
  [Required]
  string MyString { get; set; }
}

[MetadataType(TypeOf(IMyModel_ValidateMystringOnly))]
public class MyModel_ValidateMystringOnly : MyModel

This allows you to create any number of validation types, and only validate what you want when you want.

public ActionResult ShowMyModel()
{
  var model = new MyModel(); // or Respository.GetMyModel() whatever..

  View(model);
}

public ActionResult ValidateModel(MyModel_ValidateMystringOnly model)
{
  if (ModelState.IsValid)
  {
    // Hey Validation!
  }

  // MyModel_ValidateMyStringOnly is a MyModel 
  // so it can be passed to the same view!
  return View("ShowMyModel", model);
}

This is just an example, but should be clear on how-to reuse the same model with or without validation.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
1

You can use Foolproof to validate your fields conditionally. This way, they'll be required only when they need to, as you can see in the example of the link.

private class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    public bool Married { get; set; }

    [RequiredIfTrue("Married")]
    public string MaidenName { get; set; }
}

In this example, MaidenName will only change your ModelState.IsValid to false if Married == true

William Barbosa
  • 4,936
  • 2
  • 19
  • 37
1

You should always separate your VIEW model from your DOMAIN model. There is a very good reason for this and it has to do with security. When you use your domain models as your view models you are vulnerable to an overposting and/or underposting attacks. You can read more about it on these pages:

  1. http://odetocode.com/blogs/scott/archive/2012/03/12/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx
  2. http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx
  3. https://hendryluk.wordpress.com/tag/asp-net-mvc/

In short if you don't need a field then it should not be in your view model. You should convert - map your view models to domain models. Although it can be tedious it makes your application much more secure. There are libraries you can use to help you with mapping such as Automapper.

EDIT: Since my original answer, I have come to a conclusion that the easiest way to deal with this type of scenario is to have your view model implement IValidatableObject interface and then write your validation logic inside the Validate method. It does not give you client side validation but it is the most effective and clean way to accomplish custom/scenario based validation without writing your own custom filters.

You can read more about it here: http://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3

Marko
  • 12,543
  • 10
  • 48
  • 58
  • This is a view model not a domain model. Basically this is a partial view that has multiple types of inputs that user can pick from. But the number and types of inputs is configurable. But any inputs that are displayed need to be required. – Mykroft May 23 '14 at 13:53
1

I have used method at times where the form changes slightly based on specific DropDown or Radio Button selections.

Inside your Action method before you check ModelState.IsValid you can do something like ModelState.Remove("Object.PropertyName")

Note: The property name should be the same as the ID rendered to the client. Use a "." for any underscores.

    If isSomeCondition Then
        ModelState.Remove("Property1")
        ModelState.Remove("Property2")
    End If

    If ModelState.IsValid() Then
       ...
    End If
Jeremy A. West
  • 2,162
  • 4
  • 27
  • 40