Print

Integrating Enterprise Library Validation Application Block With LINQ to SQL and Entity Framework Part 1: Basic Integration

This article describes how to integrate the Enterprise Library Validation Application Block in conjunction with an O/RM technology such as LINQ to SQL and Entity Framework.

For a long time, doing a deep dive into the Enterprise Library Validation Application Block (VAB) was on my list of things to do. Especially how to place the VAB within an architectural context.

Microsoft's Enterprise Library is a big framework with useful functionality for developing .NET based applications. The Validation Application Block is part of that big framework and "provides useful features that allow developers to implement structured and easy-to-maintain validation scenarios in their applications ->". Validations can be defined using configuration files (with designer support!) or by applying attributes to classes and properties where validation support is needed. The VAB comes with a set of standard validations, but it’s possible to write your own validations and integrate them with the framework.

Instead of writing a lengthy article about the features of the VAB, I advise you to browse through the ValidationHOL.pdf document from the Validation Application Block Hands-On Labs. It gives a great overview on the main scenario's for which VAB can be used.

The scenario I find VAB most useful in, is defining validations for domain entities, such as validating classes generated by LINQ to SQL or Entity Framework. Because these two O/RM technologies generate domain entities, it’s practically impossible to use attribute based validation. Validations have to be specified in a configuration file. I personally don't mind, because this does a better job in separating the validation concern from code and enables configuring the validation using the supplied designer. Besides that, configuration based validation provides a lot more flexibility. However, the configuration based approach has it’s own pitfalls. You should definitely read this article when you’re planning on using that approach.

[Update 2010-02-10] The next version of the Validation Application Block (version 5.0) will be able to read .NET 3.5 DataAnnotations attributes. This will allow you to define your validations using the 'buddy class' technique that DataAnnotations offer. While this technique is still less flexible than what VAB can offer, nice thing is that you can mix techniques. You can use buddy classes for simple validation rules that can be picked up by ASP.NET and use VAB validators for complex business rules with possible database interaction.[/Update]

This is great, but how do we actually integrate VAB with a technology such as LINQ to SQL or Entity Framework? While it is possible to let the client invoke validation before calling the LINQ to SQL SubmitChanges or Entity Framework SaveChanges method, I prefer integrating this into the generated context class. This makes it impossible for the validation to be forgotten. Here is an example of an implementation of a partial LINQ to SQL DataContext class with validation support:

// Validation with LINQ to SQL.
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
public partial class NorthwindDataContext
{
public override void SubmitChanges(ConflictMode failureMode)
{
// Adding validation support when saving.
EntityValidator.Validate(this.GetChangedEntities());
base.SubmitChanges(failureMode);
}

// Gets the list of modified objects that are tracked
// by the current data context.
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}

And below is an example of an implementation of a partial Entity Framework ObjectContext class with validation support:

// Validation with Entity Framework.
using System.Collections.Generic;
using System.Data;
using System.Linq;

public partial class NorthwindEntities
{
partial void OnContextCreated()
{
// Adding validation support when saving.
this.SavingChanges += (sender, e) =>
EntityValidator.Validate(this.GetChangedEntities());
}

// Get the list of modified entities that are tracked
// by the current data context.
private IEnumerable<object> GetChangedEntities()
{
const EntityState AddedAndModified =
EntityState.Added | EntityState.Modified;

var entries = this.ObjectStateManager
.GetObjectStateEntries(AddedAndModified);

return
from entry in entries
where entry.Entity != null
select entry.Entity;
}
}

You can see that both frameworks have a different extensibility mechanism. While LINQ to SQL allows overriding the SubmitChanges method for injecting validation, with Entity Framework the SavingChanges event has to be hooked. Both classes implement their own version of the GetChangedEntities method to return all entities that are created or changed within the scope of the given context. Notice that deleted objects will not be returned, which hopefully makes sense.

What’s missing in the previous code snippets is the implementation of the EntityValidator class:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.EnterpriseLibrary.Validation;

// The helper class for validation entities.
static class EntityValidator
{
public static void Validate(IEnumerable<object> entities)
{
// Get a list of ValidationResults, one for each
// invalid object.
ValidationResults[] invalidResults = (
from entity in entities
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
select results).ToArray();

// Throw an exception when there are invalid results.
if (invalidResults.Length > 0)
{
throw new ValidationException(invalidResults);
}
}
}

[Serializable]
public sealed class ValidationException : Exception
{
public ValidationException(ValidationResults[] results)
: base("There are validation errors. etc. etc.")
{
this.Results = results.ToArray();
}

public IEnumerable<ValidationResults> Results
{
get; private set;
}

...
}

The EntityValidator’s Validate method validates the supplied collection of entities. I really like the expressiveness of LINQ; do you see how readable the code becomes with such a query? The result of the query is an array of ValidationResults objects, one per invalid entity. The entities are validated using a Validator instance, created by VAB’s ValidationFactory.

An important design decision here, is to throw an exception in case invalid entities are found. A context should not be able to save it’s changes, when it contains entities that are considered to be invalid as defined by the business. By throwing an exception this is communicated very clearly. This way it’s impossible for the client programmer to forget to handle this exceptional condition. Just imagine what happens when a developer forgets to handle that exceptional case. Not throwing an exception would make the user, on who’s behalf the operation is executed, believe that his changes are actually saved, while they’re not. This will result in an angry customer calling customer support. I’d rather let an exception bubble up, so it can be logged using the Enterprise Library Logging Application Block or CuttingEdge.Logging.

Finally, there need to be some code that can handle the thrown exception. How to do this depends on the type of application and it’s design. Here is a simple console application that uses the Entity Framework to create a new customer, saves it and shows the errors in case of an ValidationException:

static void Main(string[] args)
{
using (var db = new NorthwindEntities())
{
Customer junkie = new Customer();

junkie.CustomerID = "junki";
junkie.ContactName = "S. van Deursen";
junkie.CompanyName = "Cutting Edge";

db.AddToCustomers(junkie);

try
{
db.SaveChanges();
Console.WriteLine("Success!");
}
catch (ValidationException ex)
{
ShowErrors(ex);
}
}

Console.ReadLine();
}

private static void ShowErrors(ValidationException ex)
{
Console.WriteLine(ex.Message);

var errors =
from results in ex.Results
from result in results
select result.Key + ": " + result.Message;

foreach (var error in errors)
{
Console.WriteLine(error);
}
}

Please note that there are a few short comes to the given implementation:

  • It assumes the definition of a single default rule set. Rule sets are a very useful feature of VAB, but it depends on your requirements if you need them and in what way.
  • The implementation is unable to cope with validations that require database communication through the LINQ to SQL DataContext or Entity Framework ObjectContext. I will handle this in the part two.

Part two will be about using context within custom validators, part three will be about some common pitfalls when creating those custom data centric validators, part four will be about getting the most out of generated meta data and if you're interested in putting the VAB's configuration in its own file, you should read this article. When you want to integrate VAB with ASP.NET Web Forms, you should definitely read my series that start here.

Happy validating!

- .NET General, C#, Enterprise Library, Entity Framework, LINQ, LINQ to SQL, O/RM, Validation Application Block - sixteen comments / No trackbacks - §

The code samples on my weblog are colorized using javascript, but you disabled javascript (for my website) on your browser. If you're interested in viewing the posted code snippets in color, please enable javascript.

sixteen comments:

Hi,

Nice article just what I was after, however how would you validate a whole graph an entity with inheritance (i.e. I have a collection of a certain type of entity which is actually differing inherited types) and I want specific validation per entity type not just the validation on the base type?

Cheers,
Luke.
Luke (URL) - 28 04 09 - 07:27

Hi Luke. About validating a graph; you should look at the "Lab 3: Validatating Object Graphs" chapter in the ValidationHOL.pdf document that comes with the Hands On Labs (this article has a link to it). I think that chapter describes what you’re after.
About validating several inherited types; you should use ValidationFactory as I did in this article with the following code:

let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)

Like I did in this article, you will have to create a validator for each entity you wish to validate. Note that validating types with the Validator.Validate<T>(T entity) method won't work, because you fix the validation to the type T and that is the type known at design time. ValidationFactory.CreateValidator does the trick.

I hope this helps.
Steven (URL) - 28 04 09 - 21:35

How can I include an Valitator Attribute to a member in a partial class, if the member already exists in my Linq To Sql Class or in My Entity Class generated by the framework ?
Fernando Nomellini - 25 09 09 - 16:54

Fernando,

you can't. That's why I use the configuration based approach in this article. Because of this the article states: "Because these two O/RM technologies generate domain entities, it’s practically impossible to use attribute based validation."

C# and VB have no support for 'partial properties' (see: http://social.msdn.microsoft.com/Forums/..), which makes it hard to add attributes to generated code without loosing those changes after the code is re-generated.

Because of this limitation of C# and VB, .NET RIA Services use 'metadata classes' (see: http://www.nikhilk.net/RIA-Services-Flue..) to define validation attributes. Validation Application Block however, does (currently) not have the notion of metadata classes, so you're stuck with using the configuration approach.
Steven (URL) - 25 09 09 - 17:25

Thank you for your time and explanation !
I will now use configuration in my studies. But, I heard that in EF 4.0 this will be possible ! For now, I will use the aproach posted here in this blog.
Fernando Nomellini - 25 09 09 - 18:45

I can't imagine that this is possible with EF 4.0. What you're experiencing is a short come of both VAB and the mainstream programming languages, not a short come of Entity Framework. What will be possible with EF 4.0 is the validation that the .NET RIA Services will offer, but that's a simply different validation framework. Perhaps a future version of the Enterprise Library VAB will offer such a thing as metadata classes.
Steven (URL) - 26 09 09 - 00:01

What if EF 4.0 could be able to work with POCO, like NHibernate ? In this case, you can put Validation attributes in you poco class and let EF do they magic. Just a tought.
Fernando Nomellini - 26 09 09 - 02:12

You are completely right about this. EF 4.0 enables you to write POCO classes and they allow you to add your own validation attributes. Good point. Alternatively you could also define your own T4 template and let EF generate the entities including validation attributes for you (however, specifying your own template could be a bit hard).
Steven (URL) - 26 09 09 - 10:28

Yes you are right, with EF 4 now you can use POCO objects like NHibernate.
Pretty cool!
raffaeu (URL) - 01 11 09 - 12:30

I just read the the next version of the Validation Application Block (v5.0) will will be able to read the .NET 3.5 DataAnnotation attributes and this will allow you to define validations using the 'buddy class' technique. Read about it here: http://entlib.codeplex.com/Thread/View.a..
Steven (URL) - 10 02 10 - 15:59

Hi, I am realy looking forward for the 'buddy class' technique. This will be a great help for providing validators across a huge legacy system.
Søren Hardenberg (URL) - 16 03 10 - 12:44

Hi Steven

Thanks very much for this nice solution. It's very neat. Validation only has a very small finger print on the data layer. However, it'd be better if the validation logic can be totally separated from data access layer. I don't know if it's possible to use entlib policy injection to achieve this.
Binjie - 24 09 10 - 23:46

Binjie, I know too little about the policy injection block to say anything useful about this. AOP can however be an overkill. You can also wire this up using Dependency Injection. For instance, when using the Simple Service Locator (http://simpleservicelocator.codeplex.com) you can configure the Entity Framework Object Context like this:

container.Register<NorthwindEntities>(() =>
{
  var db = new NorthwindEntities();
  db.SavingChanges += (sender, e) =>
  {
    EntityValidator.Validate(
      from entry in db.ObjectStateManager
        .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
      where entry.Entity != null
      select entry.Entity);
  };
  return db;
});
Steven (URL) - 25 09 10 - 11:25

Hi, your anti-spam is not working (or working far too well!). Email me please, I have a question. Thanks.
Richard - 23 12 10 - 23:54

Thanks for the tips, will give it a go.
Thomas (URL) - 11 02 11 - 17:05

A reader of my blog warned me that the solution presented in this blog does not work directly with Entity Framework for .NET 4.0. I haven't had any time to look into this, and I'm sure that this is easily solved, but please be warned.
Steven - 25 05 11 - 23:16


No trackbacks:

Trackback link:

Please enable javascript to generate a trackback url


  
Remember personal info?

/

Before sending a comment, you have to answer correctly a simple question everyone knows the answer to. This completely baffles automated spam bots.
 

  (Register your username / Log in)

Notify:
Hide email:

Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.