ModelState not updated when deriving from DefaultModelBinder even though clientside validation fireshttp://forums.asp.net/t/1806752.aspx/1?ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesThu, 24 May 2012 14:46:56 -040018067524994201http://forums.asp.net/p/1806752/4994201.aspx/1?ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesModelState not updated when deriving from DefaultModelBinder even though clientside validation fires <p>Hi all,</p> <p>I am working in MVC 3, using DataAnnotations for clientside validation of a model that is contained inside a viewmodel (along with other items) bound to a partial view.&nbsp; I have a submit button on the partial view that does an ajax post containing a json object with the formdata.</p> <p>ie.</p> <pre class="prettyprint">public class MyViewModel { public string SelectedInstallations {get;set;} public MyModelClass Client {get;set;} } public class MyModelClass { [Required(ErrorMessage=&quot;Client Name is required.&quot;)] [StringLength(50, ErrorMessage = &quot;Client Name must be 50 characters or fewer&quot;)] public string ClientName { get; set; } [Required(ErrorMessage = &quot;Abbreviation is required.&quot;)] [StringLength(6, ErrorMessage = &quot;Abbreviation must be 6 characters or fewer&quot;)] public string Abbreviation { get; set; } public bool IsActive { get; set; } } Inside the view: $.post($(formToSubmit).attr(&quot;action&quot;), { ClientName: $(formToSubmit).find(&quot;#CurrentClient_ClientName&quot;).val(), Abbreviation: $(formToSubmit).find(&quot;#CurrentClient_Abbreviation&quot;).val(), IsActive: $(formToSubmit).find(&quot;#CurrentClient_IsActive&quot;).is(':checked'), SelectedInstallations: installations //this is populated via JS, details omitted }, function (data) { //Contents omitted }, &quot;json&quot;); return false;</pre> <p>I have created a custom model binder by deriving from DefaultModelBinder, and it is binding the object properly.</p> <p>Here's what is happening if I submit the form with bad data (in this case, no req'd fields populated):</p> <p>By the time MyModelBinder gets called, the client side validation has already occurred (I can see in the HTML that the proper validation messages are showing up).&nbsp; Then the MyModelBinder runs through and populates the model with whatever it has.&nbsp; Then it calls the action method on the controller.</p> <pre class="prettyprint"> [AcceptVerbs(HttpVerbs.Post)] public JsonResult JsonCreate(MyViewModel clientVM) { if (ModelState.IsValid) /// &lt;--- this is showing true even when it should be false! { var saveResult = _clientRepository.SaveClient(clientVM.Client); if (!saveResult.IsSuccess) { //handle errors omitted return Json(new {IsSuccess = false}); } //if we got here we succeeded return Json( new { IsSuccess = true }); } return Json(new {IsSuccess = false}); }</pre> <p><br> <br> </p> <p>The problem - in the action method, ModelState.IsValid is showing up as true even though the model has none of the required fields.&nbsp; So the controller then calls the repository to save the data, which of course fails with expected errors because it's missing the fields.</p> <p>While this might all be fine and dandy from the user perspective I want to be able to abort the attempt to save as soon as it reaches the controller -- so I need ModelState.IsValid to be set to false when the model fails validation.&nbsp; ETA: I found ModelState on the bindingContext but it is set to IsValid=true when it enters the ModelBinder despite the client validation having triggered.&nbsp; </p> <p>What can I do to ensure that the ModelState is accurate when it hits the action method on the controller in this scenario, so that the app doesn't waste time and resources trying to do the save (which in my application is a WCF service call by the repository) when it is doomed to fail, without repeating the validation in the controller and/or the modelbinder?</p> <p>Thanks in advance for your help and being patient with someone new to MVC :)</p> 2012-05-23T15:27:50-04:004995880http://forums.asp.net/p/1806752/4995880.aspx/1?Re+ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesRe: ModelState not updated when deriving from DefaultModelBinder even though clientside validation fires <p>I looked at the code in reflector and DefaultModelBinder&nbsp;'SetProperty' method is the one which is responsible for validation and set the error message.&nbsp;I understand that Model Binding and Validation are two different steps and Default Model Binder is not able to validate your model,&nbsp;there could be many reasons for this. Some of them outlined here.</p> <p><a href="http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html">http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html</a></p> <p><a href="http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx">http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx</a></p> <p>I would suggest to use the DataAnnotationModelBinder or can override the OnPropertyValidating method of DefaultModelBinder to have your validation perfromed.</p> <p>I hope this will help.</p> <p>Thanks,</p> <p>&nbsp;</p> <p>&nbsp;</p> 2012-05-24T13:17:07-04:004995894http://forums.asp.net/p/1806752/4995894.aspx/1?Re+ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesRe: ModelState not updated when deriving from DefaultModelBinder even though clientside validation fires <p>ModelState.IsValid is just a check if the error collection is empty. your binder must not be adding errors for missing required firelds. only your binder knows if the missing required were included in the postback.</p> 2012-05-24T13:22:52-04:004995970http://forums.asp.net/p/1806752/4995970.aspx/1?Re+ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesRe: ModelState not updated when deriving from DefaultModelBinder even though clientside validation fires <p>Bruce - So is what you are saying that the ModelBinder *has* to be the one to add the errors, even though the clientside validation already kicked in?&nbsp; IE in a normal &quot;DefaultModelBinder&quot; scenario using JS ajax it is still actually going to the server even if clientside validation failed, as opposed to aborting the call as soon as it saw that the validation failed?</p> <p>It seems to me that client side validation only does something useful if it prevents contacting the server at all when there is a validation problem. &nbsp; I wouldn't have thought that I should *have* to add the errors inside the model binder if the client side validation were doing its job properly.&nbsp; Otherwise, why bother doing it clientside at all, if it's going to call the server and revalidate there anyway?</p> <p>(I had already read both of the links that the CPrakash82 posted, neither applied to my scenario directly. I will try switching from deriving from DataAttributeModelBinder instead of the DefaultModelBinder though to see if I can at least eliminate some redundancy)</p> <p>Thanks!</p> 2012-05-24T14:06:37-04:004996036http://forums.asp.net/p/1806752/4996036.aspx/1?Re+ModelState+not+updated+when+deriving+from+DefaultModelBinder+even+though+clientside+validation+firesRe: ModelState not updated when deriving from DefaultModelBinder even though clientside validation fires <p></p> <blockquote><span class="icon-blockquote"></span> <h4>CPrakash82</h4> <p></p> <p></p> <p>I would suggest to use the DataAnnotationModelBinder or can override the OnPropertyValidating method of DefaultModelBinder to have your validation perfromed.</p> <p></p> <p></p> </blockquote> <p></p> <p>After doing more reading the DataAnnotationsModelBinder is the default in MVC2&#43;.&nbsp; The version you can find online was written for MVC 1 and is incompatible with MVC 3 - it required several changes to even compile and it still fails at runtime using obsolete setters.</p> <p>I *can* add model errors in my model binder manually but again, this defeats the whole purpose of having client-side validation.</p> 2012-05-24T14:46:56-04:00