Pixata Custom Controls
For Lightswitch

Recent Posts

Popular tags (# posts in brackets)

Anonymous types (3) ASP.NET (5) C# (3) C# tricks and tips (2) Computers (6) Design patterns (3) DomainDataSource (3) Dynamic data (4) Entity framework (3) Entity model framework (5) F# (3) LightSwitch (12) Linq (6) Microsoft (2) MVP (2) MVVM (2) Project Euler (2) RIA services (5) Silverlight (2) SQL Server (4) Unit testing (4) Visual Studio (7) WCF (3) WPF (3)

Gratuitous link to StackExchange




The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Actually, as I'm self-employed, I guess that means that any views I expressed here aren't my own. That's confusing!


Theme modified from one by Tom Watts
C#/F# code styling by Manoli (for posts pre-2016) and Google code prettify (for post from Jan 2016 and beyond)

My rambling thoughts on exploring the .NET framework and related technologies

Please note that this blog has ben retired. Most of the material has been migrated to my new blog at www.pixata.co.uk. Please update your bookmarks to point to the new blog.

As I mentioned in my post about the DomainDataSource control (DDS), the same RIA services toolkit that provides the DDS also supplies a validator control called the DomainValidator. As this provides such a useful piece of functionality so easily, I thought it was worth a quick post about it.

If you're familiar with ASP.NET validation, you'll know that it's really easy to add this to a page. For example, if you have a TextBox, and you want to ensure that the user enters something in it, you just add a RequiredFieldValidator control...

   1:  <asp:TextBox ID="txtName" runat="server" />
   2:  <asp:RequiredFieldValidator ControlToValidate="txtName"
   3:          ErrorMessage="You must enter your name" Text="required" runat="server" />
   4:  <asp:ValidationSummary ShowMessageBox="true" ShowSummary="true" runat="server" />

When the user clicks the submit button, if the TextBox is empty, they will get a message box pop up telling them "You must enter your name," the word "required" will appear next to the TextBox, and a bulleted list of errors (in this case only the one) will be shown where the ValidationSummary control is placed. You can easily change this if you don't want all three of these (I switch off the bulleted list and keep the other two, but that's just my preference).

This is great in that it gives both client-side and server-side validation, without you needing to write any code. The problem is that it munges the layers. Validation logic should really be in the logic layer (duh), and not in the presentation layer.

The RIA services toolkit gives you an alternative. Let's assume that the required name field above maps to a Name property on one of the entity objects in our model. Then the RIA method that inserts/updates the object could contain code like this...

   1:  public void UpdateUser(User user) {
   2:    if ((user.EntityState == EntityState.Detached)) {
   3:      if (user.Name == "") {
   4:        throw new ValidationException("The user's name must be supplied");
   5:      }
   6:      this.ObjectContext.Users.AttachAsModified(user, this.ChangeSet.GetOriginal(user));
   7:    }
   8:  }

The code in lines 1, 2 and 6-8 were all created automatically when the RIA service code was generated. All I did was add the simple validation in lines 3-5.

Now, to make use of this, we change our earlier code to look like this...

   1:  <asp:TextBox ID="txtName" runat="server" />
   2:  <cc1:DomainValidator ControlToValidate="txtName"
   3:          ErrorMessage="You must enter your name" Text="required" runat="server" />
   4:  <asp:ValidationSummary ShowMessageBox="true" ShowSummary="true" runat="server" />

Notice that there isn't any validation logic here, it's all in the RIA service, which is where it belongs. The format of this control is exactly the same as the RequiredFieldValidator, except that this is a generic validator, so doesn't include the actual logic for validation. You would use the same code for any kind of validation, and (unlike ASP.NET validators, where you need one for each validation type), you only need one DomainValidator per control.

What happens now is that if the user tries to submit the form without entering a name, the code in the RIA service throws a ValidationException, which is caught by the DomainValidator. This displays the error messages just as before.

So we have achieved a clear separation of the logic from the presentation, and done it with very little change. But wait, it gets even better :-D

Although the validation code we wrote in the RIA service was only three lines, it would be nice if we didn't even need to write this much. After all, we're busy and lazy, right? The good news is that for most basic validation, you don't even need to write any code, you just need one simple attribute.

To show this, we need to go back to when we generated the RIA service itself. To add one to your project, you choose a new Domain Service Class. This opens up a window where you can configure the service...

The window to configure the new domain service

Notice that little checkbox at the bottom? If you check that, then you will get a second file generated when you click OK. Along with the DomainService1.cs file (which is the code for the actual RIA service), you get a file called DomainService1.metadata.cs which contains (wait for it...) metadata! OK, so what the heck is metadata? Simply put, it's information about your service, and basically contains class definitions for the objects in the service.

The clever bit is that you can decorate these classes (I love that expression!) with attributes that will do the validation for you. So, if we open the metadata file for our object, we can simply add a [Required] attribute to the Name property...

   1:  [Required]
   2:  public string Name { get; set; }

Now you don't need the C# code in the RIA service, and the validation will be done for you. That's all there is to it! Actually, that's not quite true. To do the job properly, you really need to add an error message there, as you may have more than one validation on a property, and you need to be able to give a meaningful message back. You can do this by modifying the attribute like this...

   1:  [Required(ErrorMessage = "Name is required"]
   2:  public string Name { get; set; }

There are loads of attributes you can add here, such as RegEx validation, string length, range validation and so on. See the MSDN System.ComponentModel.DataAnnotations Namespace documentation for more than you'll ever need to know on the subject.

What we end up with is a very concise way of performing validation, as most of it can be done by adding simple attributes to the metadata. As mentioned before, this is all in the RIA service, which is our business logic layer, so the structure of the application remains clear, unlike with the ASP.NET validators.

The one downside to this is that (as far as I know), you can't do client-side validation this way. I really like client-side validation as it's a fast way to inform the user that something needs attention. As the validation code now all lives in the RIA service, it all happens on the server, so the user has to wait for a round trip before they see any warnings. Also, I haven't found a way to have the message box pop up when there is a validation error. I tried enabling this in the ValidationSummary control, but that generated a run-time exception when the validation fired. I would love to find a way around this, but still feel that the combination of the DomainValidator and metadata attributes gives such a powerful validation method, that it's worth the sacrifice.

Comments are closed.