All About Software Development

Menu

Validating Dependent Fields in ASP.NET MVC

In this post I wanted to describe a solution to a specific problem I recently encountered. The problem is as following. I have a class with a set of dependent properties, such as start and end date or minimum / maximum numbers. I want to implement both client and server side validation in an MVC application using attributes. I really like how attributes work in MVC application that is why I picked that specific solution. Since I want good interactive user experience, I want to make sure the same validation works in JavaScript. I am going to build my validation by plugging into jQuery validation framework.

I am now going to assume the following:

You created new MVC 3 project using Razor

I added Entity Framework to the project

I updated all packages to the latest version

Cool, now that we established ground work, le’s describe the solution. Let’s start with a Product class.

As you can see from above, I am going to create a couple of attributes, one to compare number, the other to compare dates. I am going to cover one in details, and the other one is very similar of course. To create a validation attribute, such as CompareNumbers, I am going to extend a base class, ValidationAttribute. Then, I am going to implement an IClientValidatable interface. This intercface only needs one method, the one that returns validation rules collection. In my case, I only need one rule.

First, server side. I am going to override IsValid method.and implement simple logic. To do that, I need to have access to two things, current value which is passed into this method, and the other property value that I need to compare this value to. To simplify the setup my logic assumes that if property name contains word “begin”, it would be a start (smaller value). Otherwise, I am going to assume that I am looking at the larger value of the two.

If you look at the logic, you can see that I am doing null check first, then converting current value to decimal. if you want to extend this validation to double type, you can easily do that. Also, I have a check for equal values, and in this case I am going to use explicit property value of the attribute. let me show you the entire class now:

As you can see, I have two properties that I am setting from the constructor – the other property name and a flag that allows values to be equal, which is my default. If you take a look at the last method, you can see that I am injecting those two properties’ values into the HTML of the page via jQuery validation and unobtrusive validation frameworks. Unobtrusive validation works off data-val-* attributes that MVC automatically injects for me into my HTML and jQuery parses those, establishing client side validation rules.

Here is how I am going to approach client side. I am going to write a JavaScript function, similar to IsValid method you saw above. To inject this method into jQuery validation, I just need to call two methods in jQuery: I need to add an adapter via adapters.add method that would adept data-val-* attribute values and will map them to parameters passed into my function, which in turn is added via addMethod call. Once that is done, I am going to subscribe to blur (lost focus) method of the “other” control and run its validation at that point. So, if I got it all right, as soon I change a value of Begin*** text box, then tab out, both that textbox and End*** textbox’s value will be validated by my custom method.

As you can see, I just need to le jQuery know about my property names of the original validation attribute. All values and names must be in lower case though, or you will get errors from jQuery. These values also include error message that I originally set on the attribute constructor called from my Product class (see class definition above.).

Code is pretty simple as you can see. Again, I am relying on property names (control names to be precise), but those do match because this is how MVC engine creates controls corresponding to properties. I am also doing null checks and calling parseFloat methods. I also check equality property value. I rely on the fact that in JavaScript non empty string check returns True in my if statement. The last line of code is interesting. I have a helper class that is responsible for wiring up dependent controls via addDependatControlValidaitonHandler method. let’s take a look at this helper class.

My method addDependatControlValidaitonHandler checks to see if customValidation already tracks the dependent control, and if not, adds it to wired controls collection (relatedControlsCollection property). First time validation is called, I am also grabbing validator object from the form to use with calls. This is an optimization trick. In the addDependatControlValidaitonHandler I also attach an event handler to the ‘blur’ (lost focus) event of the related control. I am using a few utility method from jQuery to accomplish that, such as on and inArray.

One nice thing I also do is to use jQuery UI framework to turn my text boxes into date pickers. To accomplish all that I am adding all my scripts and style sheets to _Layout.cshtml to avoid including them in every page.