Thursday, April 19, 2007

LINQ to Validation

I spent the weekend looking at the Enterprise Library 3.0 validation block. It's fantastic and long overdue. Developing this library was a no-brainer. I wrote something similar (though much less ambitious) as soon as I learned to use attributes in C# 1.0. Although it is a great framework as is I can't help but imagine ways in which LINQ could make it even better.

Validation has annoyed me more than any other problem with perhaps the exception of the object-relational mismatch . Validation logic should be applied at every tier: client, server, and database. However writing and maintaining the same validation rules in Javascript, a server-side language, and then again in SQL is so labour-intensive and thankless that I suspect few people actually do it.

Several attempts have been made to solve this problem in the past with limited success. Some code generators allow you to express business rules in a domain-specific language which is then translated into various target languages. There have also been attribute-based solutions that use XSL as the validation language. The problem with all these solutions is that they force the developer to use yet another language. This is necessary because the language has to be able to be expressed as data so that it can be analysed and converted into other languages. Unfortunately this means that the validation language has to be stored in config files or strings putting it out of reach of the type checking and refactoring tools available in most IDEs. Does this problem sound familiar? It should. It's the same problem we have with data access code today.

Now that LINQ is coming we will have two languages that are powerful enough to express any kind of validation rule, will have full IDE support, and can also be converted into data and thus into other languages: VB.NET and C#.

LINQ is the gift that keeps on giving. As I've written in this blog many times before, the applications for turning code into data extend far beyond improving database integration. Let's examine the ASP.NET PropertyProxyValidator control that comes with the validation block in EL3. You associate it with a property on an object and when the user attempts an action it does a server postback, calls the EL3 Validator object, and displays an error if one is encountered. This keeps you from having to create a custom validator control that performs the same validation you are already doing in your business object. However most validation (regular expression validation, string length validation) can be done in client-side code. The postback is unnecessary. Unfortunately performing the validation on the client-side means writing Javascript as well as server-side code (after all, the user's browser may have javascript turned off). Now imagine that, post-LINQ, a new validation attribute called ExpressionValidatorAttribute is added to the EL3 validation block:

public ZipCodeValidatorAttribute : ExpressionValidatorAttribute<string>
{
public override Expression<Func<string,bool>> GetExpression()
{
return x => new Regex(@"[0-9][0-9][0-9][0-9][0-9]").IsMatch(x);
}
}

Notice that we are returning a validation function as an Expression which means that it instead of returning a delegate it will return a data representation of the function. An ASP.NET validator control could retrieve the expression using reflection and convert it to the following Javascript function without breaking a sweat:

function (x){
return /[0-9][0-9][0-9][0-9][0-9]/.exec(x) != null;
}

It could then run this function on the client-side, avoiding a postback. On the server-side the validation object would just compile the expression and run it (which could be done once and cached). This would allow us to use the same code for validation on the client and server-side!

Javascript is actually a very powerful functional language. You can even translate LINQ queries to it without much effort. In fact the only validations that could not be converted to Javascript would be those that require access to some server-side resource. In practice this is rare.

Almost all validation logic is functional because it doesn't modify the state of the objects it inspects. It takes some data as an input and returns a single boolean. Therefore most validation can be expressed using lambda functions and can therefore be converted to lambda expressions. Voila! We've solved the problem of duplicated validations without having to rewrite code in different languages, learn a new language, or leave the comfort of Visual Studio.

10 comments:

Anonymous said...

Actually I've found cross-tier validation to be something of a no-brainer. Previously with ASP classic, we used regular expressions in a javascript file that with some creative use of comment tags could be used unmodified on the client and the server. For the database tier and now with CLR integration in SQL Server, it is possible to use .Net Framework regular expressions as constraints. Perfect for ensuring data integrity inside your database.

Jafar Husain said...

Regular expressions work reasonable well for validation on single fields. Of course things like date-bounding can't be done that way. What's interesting about the method I outline is that you can use for business rules instead of just single field data validation. For example: "if a customer's payment method is credit card their orders must total to over $20."

Using LINQ this is easy:

customer => customer.PaymentMethod != PaymentMethod.CreditCard || (customer.PaymentMethod == PaymentMethod.CreditCard && customer.Orders.Aggregate(o => o.Price) > 20);

Anonymous said...

Yes agreed, I guess my point was that validation has never annoyed me as much as it has obviously annoyed you and that there have been mechanisms available previously to make validation less of a chore.

Regular expressions are a useful tool for basic field validation that can be used mostly unchanged across multiple tiers. Obviously they can't get close to the example you provide. But the example is a business rule and the distribution/enforcement of business rules across tiers is a sticky issue.

Jafar Husain said...

Can you elaborate on what you mean by "sticky issue"? Specifically what concerns do you have about doing validation on multiple tiers? It seems to me that if you can push business logic to the client (and repeat the process on the server) and save a postback it is a win.

Anonymous said...

I love the idea. Especially if we can get serializable expression trees we can pass around different layers.

Anonymous said...

I'd really like to see a sample of converting an expression tree to Javascript!

Anonymous said...

Has there been any progress on this. I'm putting validation into the LINQ partial classes, which I do like, but wanted to pass this validation to the presentation tier as well. Just following up to see if you've gotten any further with this idea or have found a solution?

Jafar Husain said...

Alas no. I actually got a prototype up and working not long after this post and was successfully converting LINQ expressions into Javascript. I'd also modified the EL3 validator to push the javascript to the client. I wasn't completely satisfied with the solution because the supporting Javascript library I'd developed (in which I'd implemented lazily-evaluated LINQ for Javascript) wasn't well-integrated with ASP.NET AJAX. Unfortunately I'm embarrassed to admit that my hard drive crashed and I didn't properly back things up.

I would've picked it up again but it looks like MS is developing a much more comprehensive solution to this problem with Volta. Erik Meijer never ceases to amaze.

Anonymous said...

Women’s nike tn Shox Rivalry est le modèle féminin le plus tendance de baskets pour le sport. tn chaussuresConcernant la semelle :Cheap Brand Jeans ShopMen Jeans - True Religion Jeans nike shoes & Puma Shoes Online- tn nike, le caoutchouc extérieur, l’EVA intermédiaire et le textile intérieur s’associent pour attribuer à la.ed hardy shirts pretty fitCharlestoncheap columbia jackets. turned a pair of double plays to do the trick.Lacoste Polo Shirts, , Burberry Polo Shirts.wholesale Lacoste polo shirts and cheap polo shirtswith great price.Thank you so much!!cheap polo shirts men'ssweate,gillette mach3 razor bladesfor men.As for

Anonymous said...

情趣用品|情趣用品|情趣用品|情趣|情趣用品|情趣

About Me

My photo
I'm a software developer who started programming at age 16 and never saw any reason to stop. I'm working on the Presentation Platform Controls team at Microsoft. My primary interests are functional programming, and Rich Internet Applications.