What Do We Want in Silverlight Validation?

Url: http://niagara.codeplex.com

Niagara Project

As I've been on the mend lately, i've been looking deep into how Validation should work in Silverlight. As I am trying to expand some of hte validation scenarios in Silverlight (in my Niagara project), I'd like to see how you are feeling about Validaiton.

Currently (as my previous post mentioned), the current validation stack is pretty tightly coupled to RIA Services (though with some work you can get it working with other data stacks).  But the question is really which validation stack does Silverlight really need. Let's discuss the two I've been looking at: DataAnnotations and Enterprise Libraries' Validation Application Block.

DataAnnotations

Let's talk history. Back in .NET 3.5 SP1 (ok, I know many of you are still in .NET 2.0, my apologies), the DataAnnotations assembly was shipped. My assumption that this was to accomodate the newly christened Dynamic Data Web projects. Dynamic Data needed a way to communicate information it couldn't discern (like required fields, string length, etc.) The way that it did this was via a set of attributes in the System.ComponentModel.DataAnnotations. For example:

public class GameInfo
{
  [Required]
  [StringLength(100)]
  public string Name { get; set; }

  [Range(0d, 1000d)]
  public decimal Price { get; set; }
}

The problem with this approach was that in most cases, the classes were generated via an ORM (LINQ to SQL, Entity Framework, etc.) and adding these attributes on generated code just doesn't work. So someone came up with a workaround (or a hack if you prefer): the Metadata Type.

The idea behind a metadata type was that with partial types, users can add attributes to a class (but not a property) so by adding an attribute to each entity class that said, the metadata (e.g. validation attributes) for this class are stored in this metadata type that is never used except as a payload for the metadata about our entity.  For example:

[MetadataType(typeof(Game.GameMetadata))]
public partial class Game
{
  internal sealed class GameMetadata
  {
    // Metadata classes are not meant to be instantiated.
    private GameMetadata()
    {
    }

    public string Description;

    public string Developer;

    public EntityState EntityState;

    public int GameID;

    public Genre TheGenre;

    public string ImageUrl;

    [Required]
    [StringLength(100)]
    public string Name;

    [Range(0d, 2000d)]
    public Nullable Price;

    public string Publisher;

    public Rating TheRating;

    public Nullable ReleaseDate;
  }
}

Early on, using the metadata classes to add these bits of data may have made sense because the sites you were creating were quick and dirty data editing sites. The problem is that this stack was adopted by RIA Services to allow for better validation in the Silverlight space (and eventually other platforms).

The DataAnnotations in RIA Services are a bit fractured as well. There are no less than three versions of the DataAnnotations that can cause confusion. The atttributes lists are different in these three versions:

  • .NET 3.5 SP1's System.ComponentModel.DataAnnotations
  • RIA Services's System.ComponentModel.DataAnnotations
  • Silverlight's System.ComponentModel.DataAnnotations

The three versions can cause some confusion as the attributes that you can use are duplicative (See .NET 3.5 SP1's Description attribute versus RIA Service's as an example).

The current Silverlight validation stack relies on exceptions to be thrown during set property setters (or you can validate the whole objects yourself). While this works, it does seem at odd with the work at hand and having a simple Validation model that returned results would be better IMHO. I understand that RIA Services was trying to fit into an existing Silverlight model but that doesn't mean I have to like it.

This stack may be good enough, especially with the ability to do custom validation with RIA Services but I sense that it may be too shallow for real validation.

Enterprise Library's Validation Application Block

On the other side of the coin is the Patterns and Practice team's Validation Application Block (VAB). This is a set of code that allows you to specify validation using either attributes or configuration files. While the Validation Application Block doesn't support Silverlight directly, I've been investigating it as an alternative design.

The Validation Application Block's design is focused on some of the same principals as the DataAnnotations but they were trying to solve some different problems.  Some of the features of that design that may be of use in Silverlight are:

  • Multi-level validation (e.g. Validates with And/or clauses: "NULL or StringLength 5-25")
  • Configuration doesn't rely on attributes but can use them
  • Uses a provider model for specifying the validation so other sources of validation metadata are possible
  • Large number of built-in validations
  • Support for multiple sets of validation (RuleSets)
  • Validation is object-based to allow for cross validation (Either Name or CompanyName but not be null).
  • Fail-over validation detection (e.g. look for attributes, if not found look up configuration, etc.)
  • Validation returns simple ValidationResults which can be parsed or shown to the user. No Exceptions requried.

For example a typical attribute scenario for validation looks a lot like the RIA Services' approach:

[StringLengthValidator(1, 50, 
  Ruleset="RuleSetA", 
  MessageTemplate="First Name must be between 1 and 50 characters")]
public string FirstName
{
    get { return firstName; }
    set { firstName = value;  }
}

[StringLengthValidator(1, 50, 
  Ruleset = "RuleSetA", 
  MessageTemplate = "Last Name must be between 1 and 50 characters")]
public string LastName
{
    get { return lastName; }
    set { lastName = value; }
}

[RelativeDateTimeValidator(-120, 
  DateTimeUnit.Year, -18, DateTimeUnit.Year, 
  Ruleset="RuleSetA", 
  MessageTemplate="Must be 18 years or older.")]
public DateTime DateOfBirth
{
    get { return dateOfBirth; }
    set { dateOfBirth = value; }
}

[RegexValidator(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", 
  MessageTemplate="Invalid e-mail address", 
  Ruleset = "RuleSetA")]
public string Email
{
    get { return email; }
    set { email = value; }
}

[ObjectValidator("RuleSetA", Ruleset = "RuleSetA")]
public Address Address
{
    get { return address; }
    set { address = value; }
}

[RangeValidator(0, RangeBoundaryType.Inclusive, 
  1000000, 
  RangeBoundaryType.Inclusive, 
  Ruleset = "RuleSetA", 
  MessageTemplate="Rewards points cannot exceed 1,000,000")]
public int RewardPoints
{
    get { return rewardPoints; }
    set { rewardPoints = value; }
}

In addition it supports a configuration-based solution:

 <validation>
    <type assemblyName="ValidationQuickStart.BusinessEntities, 
                        Version=1.0.0.0, 
                        Culture=neutral, PublicKeyToken=null"
          name="ValidationQuickStart.BusinessEntities.Address">
      <ruleset name="RuleSetB">
        <properties>
          <property name="City">
            <validator lowerBound="1"
                       lowerBoundType="Inclusive"
                       upperBound="30"
                       upperBoundType="Inclusive"
                       negated="false"
                       messageTemplate=""
                       messageTemplateResourceName=""
                       messageTemplateResourceType=""
                       tag=""
                       type="Microsoft.Practices.EnterpriseLibrary.
                         Validation.Validators.StringLengthValidator, 
                         Microsoft.Practices.EnterpriseLibrary.Validation"
                       name="String Length Validator" />
            <validator characterSet="1234567890!@#$%^&*()-="
                       containsCharacter="Any"
                       negated="true"
                       messageTemplate="City may not contain numbers"
                       messageTemplateResourceName=""
                       messageTemplateResourceType=""
                       tag=""
                       type="Microsoft.Practices.EnterpriseLibrary.Validation.
                         Validators.ContainsCharactersValidator, 
                         Microsoft.Practices.EnterpriseLibrary.Validation"
                       name="Contains Characters Validator" />
            <validator negated="false"
                       messageTemplate=""
                       messageTemplateResourceName=""
                       messageTemplateResourceType=""
                       tag=""
                       type="Microsoft.Practices.EnterpriseLibrary.Validation.
                         Validators.NotNullValidator, 
                         Microsoft.Practices.EnterpriseLibrary.Validation"
                       name="Not Null Validator" />
          </property>
      </ruleset>
    </type>
  </ruleset>
</validation>

This syntax while it works, its pretty terse and unreadable (as configuration tends to be). But it is decoupled which is nice.

While many of these features are laudable, it feels a bit over-engineered and complex.  The VAB uses Validators for a number of cases where its just a grouping technique so debugging individual validations can be complex.

"Just Right?"

So here is where I put it to you, my readers:

"What do you need in Silverlight?"

  • Is the RIA Stack good enough?
  • Do you want validation regardless of what the transport is (ADO.NET Data Services, WCF, REST)?
  • Is using  RIA Services' CustomValidation with method name good enough for custom scenarios?
  • Do you need complex validation (where AND/OR validation is necessary)?
  • How important is decoupling your validation metadata from the model?
  • Do you detest metadata types or is it just a necessary evil?

Please comment here so we can start a dialogue to help me understand what the development community is thinking about validation.

 

 

Comments

Gravatar

Nikhil Kothari Tuesday, October 6, 2009

You should include deriving from ValidationAttribute as well to the mix in addition to CustomValidation.

That is the mechanism for folks building reusable validation rules, plugging in rules engines etc. etc.

You also need to position metadata types in the right context - they are one, not _the_ mechanism for plugging in metadata. The heart of the system revolves around the notion of metadata and a uniform API, rather than a particular persistence and authoring mechanism, whether it be IL, or XML, or other thing.

Gravatar

SmartyP Tuesday, October 6, 2009

I am not a fan of the built in validation for several reasons, but for the most part i've figured out intermediate solutions.. our sore spot right now is doing validation at a kepressed level and not a losing focus level.. real time feedback and validation seem key for a more responsive experience..

Gravatar

Martin Nyborg Tuesday, October 6, 2009

We are using Fluent Validation and have build a CSLA like rule manager around it. And it's a dream to work with.

Works in SL and on the server. We are using NHibernate with WCF - and no DTO's -:)

Gravatar

Shawn Wildermuth Tuesday, October 6, 2009

Martin,

Are you using the RIA Services through WCF? Or WCF directly to the Silverlight client?

Gravatar

Cristovao Morgado Tuesday, October 6, 2009

And how about multilanguage? as "MessageTemplate" is on the business object... any thoughts about this?

Gravatar

Lost in Validation Wednesday, October 7, 2009

Need a consistent approach provisioning the following:
1) validation support in getter vs. just setter. Perhaps there is a why I just can't seem to make it work right.
2) validation of complext types such that class A is comprised of fields name, age, etc. where each of these are complex types, something like the following:
class A
{
public DetailedItem Name{set; get;}
public DetailedItem Age{set; get;}
public DetailedItem JobCategory{set; get;}
}
public class DetailedItem
{
object Value{get; set;}
string Description{get;set;}
DateTime ChangedDate{get;set;}
}

Gravatar

Shawn Wildermuth Wednesday, October 7, 2009

Cristovao,

Multilang is actually supported. Aside with MessageTemplate is the MessageTemplateResourceName and MessageTemplateResourceType.

Gravatar

Shawn Wildermuth Wednesday, October 7, 2009

Lost in Validation,

I don't quite understand what yuo're getting at. Could you reword it?

Gravatar

Lost in Validation Wednesday, October 7, 2009

Given the sample, you can't simply decorate each property in Class A with DataAnnotations and expect them to propogate to validate the "Value" property of the associated DetailedItem. You also can't decorate the properties of the DetailedItem with DataAnnotations as this would apply to every instance. Does this help?

Gravatar

Shawn Wildermuth Wednesday, October 7, 2009

Lost,

If you set the DetailedItem's properties with the attributes, it should validate it. Though they are different levels so I don't think it should work that way. But I might be still confused. But thanks for the feedback.

Gravatar

Jonathan van de Veen Thursday, October 8, 2009

I feel that validation should be seperated from whatever data stack. I also think that it's just ugly to use exceptions for validation, because in this way you are effectively using exceptions as part of your program logic, which is abusing exceptions.
We do need complex validations. LOB applications are in desperate need for this.
I don't think having validations in the model is always a bad thing. In our case we code generate some of these validation attributes right into the model, which saves a lot of effort.

Gravatar

Henrik Söderlund Thursday, October 8, 2009

We need better support for asynchronous validation in Silverlight, like making a server call to see if an entered username is unique.
I am also missing the possibility to manually set something to valid/invalid from outside the container entity. It is simple enough to throw a ValidationException (even though I agree it is ugly) from inside a property setter in an entity, but I cannot see a way of setting that same property to valid/invalid from outside that entity. If this was possible, it would also be a lot easier to manually do asynchronous validation, even though I realise that this would not conform very well to the MVVM pattern.

Gravatar

Steve Hobbs Thursday, October 8, 2009

For me, throwing exceptions from property setters is a no-go since 99% of the time I'm working with entities generated by an O/R mapper. Attribute-bases validation doesn't quite cut it either because most of the time my entities are being served across WCF from a domain tier, which must also support other clients (a website, usually) and means that all the validation has to be done as part of the domain logic.

Usually what I'd do in that case is modify the entity and send it back to the domain tier for updating. If any properties are invalid then I send a collection of validation rule violations back to the client. From this I can tell which property broke a rule and what the violation message is. However, the only thing I know how to do with the Silverlight client at the moment is put those messages into a list and display the list at the top of the form/page. I'd like to be able to mark the textboxs/input controls as being valid aswell, but it seems like a difficult thing to do without throwing exceptions from property setters.

Would future clients be able to support this scenario?

Gravatar

Heather Nolan Thursday, October 8, 2009

I would also like to see a more fluid way of returning a stack of validation errors back to the client and have the UI controls updated respectively. Throwing exceptions in property setters is something we have avoided for years (prior to Silverlight and for many reasons).

I would like to see a better way to handle and display client-side validation but then allow more complex server-side validation errors be returned and presented to the user in the same manner.

Gravatar

Henrik Söderlund Thursday, October 8, 2009

The current Silverlight mode of validation where it all happens in the entities and is automatically propagated to all layers of the application is of course excellent in theory. The sad reality of things is that many of us cannot afford to rebuild our existing apps from the ground up to support this. I'm working with an app where the services and entity layers were built some time ago, with no real thought given to Silverlight. There are 300+ entities in our app. Going through all of these to add validation rules is just not possible. My situation is similar to Steves in that I get validation errors returned from the server, and want to mark the correct input controls as being valid/invalid. I feel that a decent validation framework must be able to support this scenario as well.

Gravatar

Paul Friday, October 9, 2009

My team is using CSLA for all validation and it works well since CSLA validation rules are wired into it's managed property system.
We also get the benefit of the same code being usable on the server and the Silverlight side.

The latest beta of CSLA 3.8 now supports data annotations, which is great since we can now use the attribute based approach for simple validation while retaining the normal CSLA business rules approach for complex and multi-property validations.

In terms of the built-in validation in SL3 - I'm still shaking my head at having to throw errors to trigger validation. Seems like a half-assed job to me.
We don't use it at all mainly because there is currently no way to invoke validation in the UI controls without throwing exceptions.
If there were methods to call which would enable me to manipulate the validation states on controls, then I'd use that part at least...

The built-in validation also doesn't support the concept of levels or degrees of validation. For example informational, warning and error validation.
You just get error validation with SL3.

Ultimately, for our project - a very large LOB suite port to Silverlight - we have subclassed all the standard controls and styled in our own validation layer to enable us to wire into CSLA and show validation of varying levels while not having to throw exceptions.


Gravatar

Steve Tuesday, October 13, 2009

"The problem with this approach was that in most cases, the classes were generated via an ORM (LINQ to SQL, Entity Framework, etc.)"

And therein lies the problem... It's so known of how bad a practice this is that the entire EF vNext blog posts you see is all about how great that EF is going POCO...

All lessons learned that were ignored on current releases.

I think some of this comes from a MS approaching this as a model driven design vs. domain driven design. To me, these are domain "business" entities, not just data entities - ie. not datasets.

Just to add to the conversation: Outside of Enterprise framework, NHibernate has validators as well: http://nhforge.org/wikis/validator/nhibernate-validator-1-0-0-documentation.aspx

Gravatar

Andrew Veresov Friday, November 27, 2009

Henrik, Steve
You could set validation error on any control. Validation.ErrorsProperty is public accessible and the only trick you need to do is to build ReadOnlyObservableCollection<ValidationError> collection. You could find example and validation workaround library here: http://blog.andrew-veresov.com/post/Silverlight-3-Validation-Workaround.aspx

Yeah, it is still a workaround but it could be helpful in some scenarios.

Gravatar

Ali Asgar Tuesday, December 29, 2009

i am trying to use metadata to cause validation but its not working ... as when i click on my submit buttom instead of showing the error message it shows a blank page... plz help...

Gravatar

Braulio Thursday, January 7, 2010

I think the configuration-based validation fits well when you have "generic" entities, in my case I need to have "n" columns and depending on the template a client chooses this columns will have to pass a set of validations or another one, so configuration based seems to fit pretty well.. I would only have to worry about asking to each dev team to send me an XML file with the validations the want to apply. For a normal LOB scenario I agree with you overengineer.

About the validation app block, is there anything done to adapt it or any similar library for SL? I'm thinking about developing my own validation block, but that sounds like reinventing the wheel.

thanks
Braulio

Gravatar

Vasant Javle Tuesday, January 12, 2010

I have not used CSLA based blocks.
We are looking into standardizing our validation code as well.
What I like about RIA services validation is that Validation based on attributes works well on both layers of all (i.e. SL UI as well as Server Side).
But RIA validation falls short when it comes to complex validations (like and/or). Plus RIA validations is not configuration based as far as I know.

So far Validation blocks have won my appreciation due to it's declaritive and pluggable nature of validations.
The 2 main drawbacks I would like to see it overcome in some next release is that:
Either Validation blocks supplement RIA validations declaratively and/or they include Silvelight UI validations as well.

Also Validation blocks lack of method argument validations. It would be great if they would add this capability as well.

I was able to add method validation capability in a prototype project using PostSharp method interception. But it is still code based. I would like to see this applicable declaratively out of the box with validation blocks.

Thanks
-Vasant

Gravatar

cesnek Wednesday, October 13, 2010

In my mind there is two parts of problem.

First is data description eq precision of C# types.
String has maximum 10 chars. Number has five-point-two format (12450.25). Number is positive. This information must understand UI components and forbid entering invalid values (on keypress, not on lost focus). The more data types is precised the less extra validation is needed.
(Borland Delphi done this right.)

And second part of validating problem is business validation (complex validation, server validation, etc ..)
This is not only about flat DTOs. This also about hierarchical ViewModels. For example we have ViewModel composed of two sub ViewModels. Master ViewModel is valid if sub-ViewModels is valid. And sub-ViewModels is valid when all properties is valid and so on ...
Just now FluentValidation approach make best sense for me. (For second part of validation problem.)

Gravatar

Azad Tuesday, October 4, 2011

I used wcf service in silverlight client and try to validate data in my Business layer entities using data annotation but no luck.
Any idea how can i use validation with wcf service.


Leave a Comment

*
*
*