.NET RIA Services: intermediate model validation.

I'm not the first person firmly believing that validation should be mostly entity-based, not UI control-based. It's the object who must tell the system what kind of values should its field accept, user interface should only display this info. Microsoft Enterprise Library Validation Block was a serious step in the right direction, but uniform handling of data-based validation exceptions in user interface required quite a bit of custom coding there - just to make your UI know that the data was invalid.

Now, with validation attributes in System.ComponentModel.DataAnnotations namespace uniformly supported both in Silverlight (through .NET RIA Services) and in ASP.NET Dynamic Data, Microsoft makes even more serious step in supporting entity-based validation.

Although .NET RIA Services is still in a preview phase, it's pretty obvious just how powerful this new concept is. It's not only simple, straightforward and easy to implement - it's also highly customizable. One scenario I want to discuss here as an example of its flexibility is when you need to bind your controls to some kind of intermediate data model RIA DomainService knows nothing about.

It happens pretty often - for example, when you have to cancel your changes and you don't want to spoil your real data with user's output. So you are storing your data inside an intermediate model, but in this case intermediate model should somehow "inherit" validation logics from the real object it represents. Why? Because validation attributes can often be changed - for example, you may change the ErrorMessage, or to localize it in a certain way. It'd be sheer insanity to duplicate the validation logics of specific fields in your intermediate model.

So what should we do? There are 2 ways to deal with this issue.

  1. Use an instance of the same RIA entity as an intermediate model, just don't add it to your DomainContext data collection: create it internally, and use it internally. This way, Ria will never know it exists, will never trace its changes, and will never try to store it on a server. But this internally created object will have all regular validation logics you'll need, so when you'll need to actually store its data, you'll only have to add it to DomainContext data collection - or copy data from your intermediate object to another that you'll actually store.
  2. If you still need to mimic your entity validation in intermediate model of another type, you can do it quite easy with a custom code like this:
class Model
{
    private MyEntity _actualEntity;
    ...
    public string ModelField1
    {
        ...
       set
        {
               ValidationContext context = new ValidationContext(_actualEntity, null, null);
               context.MemberName = "MyEntityField1";
               Validator.ValidateProperty(value, context); //here the proper ValidationException is thrown
                ... //store the actual value inside your Model
        }
    }
//repeat this code in setter of every entity's property you are trying to mimic in your Model
}

Of course, the first method is preferable: this way you won't need the workaround code at all, but the ability to mimic other class validation may be quite handy sometimes.