Posts Tagged 'Validation'

How to Use ViewModels Without Sacrificing Encapsulation

I have been using ASP.NET MVC extensively over the past year, and the more I use it, the more I like it. However, there remain a couple of things that bug me. One is the fact that the built-in validation doesn’t work with repeating forms. The other is the “best practice” of placing Data Annotations on a ViewModel class.

For me, validation rules belong on the business object itself, not on the ViewModel. One of the key benefits of encapsulation is that we reduce code duplication. If we don’t encapsulate the validation rules inside the object, then we are doomed to repeat them once for every presentation layer. Data Annotations in an MVC ViewModel are not available to a WPF UI. Not only does this lead to redundancy, it increases the risk of inconsistencies cropping up between UI.

So no problem, you might think. All we have to do is add the Data Annotations to the Model itself, and then add the Model as a property of the ViewModel.

Okay, let’s try that.

Here is the Model:

BasicClass simple C# class

And here is the ViewModel:

The ViewModel class

This looks straightforward enough. But look at what happens when we ask Visual Studio to scaffold the View:

View scaffolding

What happened to our “Basic” Model property? It’s not there. The scaffolding only seems to work for simple properties.

Okay, so let’s add the details of the Model to the View. In fact, let’s cheat. We’ll get Visual Studio to scaffold the inner Model for us. First we’ll create a throwaway View. Then we copy the contents of the form and paste it into the View that’s typed to the ViewModel. All we have to do then is change the lambda expressions to point at model.Basic rather than just model:

Full scaffolding

Problem solved. The View now contains the data we need and also respects our data annotations…

This means we can pass the ViewModel through to a Controller method and pick up the Model we need via the ViewModel’s “Basic” property. There’s only one problem:  How do we use the UpdateModel() method when we’re only interested in a property on the object passed to the method, rather than the whole object? Fortunately, Microsoft anticipated the need and there’s an overload on UpdateModel() that allows us to specify a prefix. In this case, not surprisingly, the HTML helpers have inserted the prefix “Basic”:

UpdateModel() with second argument

As you can see, the Model has successfully been bound, so we now have a mechanism for taking advantage of ViewModels without sacrificing encapsulation.

Kevin Rattan

For related information, check out Building Web Applications with ASP.NET MVC from Learning Tree.

Validating That At Least One TextBox Has Content

I came across an interesting little validation problem on my current project. The site is for members only – and in order to become a member, you need to be nominated. You can provide either one or two nominators, but you must provide at least one.

So how to force users to enter text in either of two TextBoxes? RequiredFieldValidators won’t do, because either one can be left empty. Yet at least one must be completed. Clearly this is a job for CustomValidators.

The client-side and server-side code are both fairly straight-forward, but I thought someone out there might find it useful, so here it is.

First of all, the CustomValidators in the ASPX page:


<asp:CustomValidator ID=”Nomination1CustomValidator” runat=”server” Display=”None” ValidateEmptyText=”true” ClientValidationFunction=”CheckNominations” ErrorMessage=”At least one nomination must be provided” ControlToValidate=”Nominated1TextBox” OnServerValidate=”Nomination2CustomValidator_ServerValidate”></asp:CustomValidator>


<asp:CustomValidator ID=”Nomination2CustomValidator” runat=”server” Display=”None” ValidateEmptyText=”true” ClientValidationFunction=”CheckNominations” ErrorMessage=”" ControlToValidate=”Nominated2TextBox” OnServerValidate=”Nomination2CustomValidator_ServerValidate”></asp:CustomValidator>

Note the empty ErrorMessage in the second validator. Combined with display=”none’, that means our ValidationSummary control is only going to display one error message to the user, making it much less confusing. Also notice that ValidateEmptyText is set to true – otherwise, our code will never run.

Then the JavaScript. We’re validating two controls, so even though we use the standard signature the validators are expecting, we’re only interested in the args. I set the TextBoxes’ ClientIDMode to static and used jQuery to get the controls.  (I use jQuery for pretty much all my client-side code).

function CheckNominations(sender, args) {
  if ($(‘#Nominated1TextBox’).val() == “”
      && $(‘#Nominated2TextBox’).val() == “”) {
        args.IsValid = false;
  }
   else {
args.IsValid = true;

   }

}

And, of course, we also need to implement the server-side code for a complete solution:

If String.IsNullOrEmpty(Me.Nominated1TextBox.Text) And
String.IsNullOrEmpty(Me.Nominated2TextBox.Text) Then
        args.IsValid = False
Else
        args.IsValid = True
End If

So now the user must fill in one of the TextBoxes, but can pick either one.  I have been using ASP.NET MVC a lot recently, and it’s nice to go back to Web Forms and see how very easy it is to take built-in controls like the custom validator and use them to meet your specific needs.

Kevin Rattan

For related information, check out these courses from Learning Tree:

Building Web Applications with ASP.NET and Ajax

jQuery: A Comprehensive Hands-On Introduction

Data Annotations and ASP.NET MVC Validation

I’m a big fan of validation using Data Annotations as used in Silverlight, WPF and ASP.NET MVC (and, hopefully, eventually ASP.NET Web Forms as well). I love the elegance of placing the validation rule directly inside the business object. To me, validation is a form of business rule, and proper encapsulation means putting the rules within the business object. Of course, the fact that the tools pick up on the Data Annotations and automatically integrate the rules into the UI really helps: without that, Data Annotations would be a great idea, but Too Much Work. ASP.NET MVC can pick up Data Annotations on both the server and the client, thus leading to nicely separated, elegant code.

The only trouble is, sometimes it doesn’t work.

If you’ve never seen Data Annotation validation, here is what the attributes look like when decorating a property:

the 'Required' data annotation

On the server-side, ASP.NET MVC will automatically add errors to the ModelState based on the Data Annotations – so in the example, an empty string would lead to ModelState.IsValid being false. On the client-side, you can optionally get ASP.NET MVC to inject jQuery-based JavaScript into the page to prevent the form being submitted until it is valid. Usually.

The problem lies in the way the validation has been implemented. It works fine for most circumstances, but not if you have repeating forms on the page.

The code to insert the validation error into the View is as follows (regardless of whether the error was picked up on the server or the client):

Html helper for validation messages

This writes out the appropriate validation for a form element with the ID Name. And therein lies the difficulty.

IDs must be unique on a page. So if you have multiple instances of the same form on a page, you have to change the IDs of the form elements to give unique IDs (Name1, Name2 etc). The problem is that the client-side validation code relies on the value of the ID attribute matching the name of the property on the bound object. But if you are binding multiple forms to different instances of the same object, you can’t have the ID match the object property, or you’ll have invalid HTML.

I came across this situation recently in the game application I mentioned in an earlier post – a version of Chutes/Snakes and Ladders. The user can have as many games as they like – so the same form is needed as many times as there are games:

repeating forms inside the game CMS

It’s an unfortunate problem, as IDs shouldn’t matter in validation – Names should. Forms send Name/Value pairs up to the server, not ID/Value pairs. Names do not have to be unique on the page, just inside the form. So if the validation code had been based around the Name attribute matching the object property, the problem would not have arisen.

So what’s the fix?

There are two obvious approaches. The first is to create your own version of the validation code and use Names rather than IDs. That would be the most elegant solution… but it’s also a lot of hard work. The alternative is to implement client-side validation some other way, such as using the jQuery Validation plugin.

I chose to use the Validation plugin – but even so, I still had some extra work to do when creating my widgets in order to avoid having badly formed HTML. The problem is that if you do this:

Html helper EditorFor

Then you end up with both ID and Name equal to “Name” (since that was the name of the property on the Model) – and we’re back to badly formed HTML. However you choose to manage your validation, you still need to create unique IDs while leaving the Name as it is (so the server-side method parameter binding works). You can either use the overloaded version of EditorFor() thus:

EditorFor using overload to add unique id and jQuery validation

Or just build it yourself out of HTML and Response.Write thus:

Response.Write version of creating unique id and adding validation

Either approach will end up with the same HTML on the client:

output HTML from the two approaches

(The object literal in the class attribute contains the validation rules for the Validation plugin, and can be extracted using the Metadata plugin. Both plugins are covered, along with a great deal else, in Learning Tree course jQuery: A Comprehensive Hands-On Introduction.)

In most circumstances, Data Annotations are the right solution for both server and client validation – but once you do something a little unusual (like repeating forms) you may find you have to do a little fancy-footwork to achieve the result you have in mind.

Kevin Rattan

For other related information, check out this course from Learning Tree:

Building Web Applications with ASP.NET MVC


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 245 IT and Management courses, including a full curriculum of over 15 .NET training options.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 9 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

Follow

Get every new post delivered to your Inbox.