Validation

Context

DevForce defines two types of validation. Property level validation and instance level validation.

Property level validation executes automatically before and/or after a property value is changed. This validation automatically occurs on the client and results in immediate feedback to the UI. Instance level validation is performed on the server before an entity is persisted to the database. The purpose of instance level validation is to make sure that an entity and it’s related entities are in a valid state in order to maintain data integrity. This approach ensures that no invalid data gets passed the server, but doesn’t give the UI much control. The server simply throws exceptions. It is often desired to perform the instance level validation on the client as well before a save.

To learn more about how to define validation rules in DevForce visit http://drc.ideablade.com/xwiki/bin/view/Documentation/validate.

Enable client-side instance level validation

The DevForce Application Framework has support for client-side instance level validation. To turn on validation the application must provide an implementation of IVerifierResultNotificationService through which it is notified of any validation error.

Note:  The application can have more than one implementation of IVerifierResultNotificationService. Each implementation will be notified.

    
public class VerifierResultNotificationService : IVerifierResultNotificationService
{
   public void OnVerificationError(VerifierResultCollection verifierResultCollection)
   {
      // Do something. For example display a popup with the error messages
   }
}

The save operation is automatically cancelled if any validation errors occur.

Custom validation

Writing complex cross-entity instance-level validation can at times be a little daunting using the DevForce Verifiers. Although, a lot can be done with the DelegateVerifier<T>, the DevForce Application Framework offers an alternative, more linear approach to writing the validation logic.

The framework provides an Interface called ICustomVerifier, which can be implemented on any entity. The interface has a single method, which will be called during the save, in addition to executing all the DevForce Verifiers. This approach allows one to mix and match by using DevForce Verifiers for simple validation and the custom validation interface for more complex validation logic.

public partial class Order : ICustomVerifier
{
    public void Verify(VerifierResultCollection verifierResultCollection)
    {
        if (OrderDetails.Count == 0)
            verifierResultCollection.Add(new VerifierResult(VerifierResultCode.Error,
                                         "Order must have at least one lineitem", "OrderDetails"));
    }
}

Executing custom validation on server

It is good practice, to make sure the server also knows about the custom validation and executes it before saving an entity. In order to execute the custom validation logic on the server, an EntityServerSaveInterceptor needs to be implemented like so:

public class SaveInterceptor : EntityServerSaveInterceptor
{
    protected override bool ValidateSave()
    {
        base.ValidateSave();

        // Find all entities supporting custom validation                
        var entities =
            EntityManager.FindEntities(EntityState.AllButDetached).OfType<ICustomVerifier>().ToList();

        foreach (ICustomVerifier e in entities)
        {
            EntityAspect entityAspect = EntityAspect.Wrap(e);
            if (entityAspect.EntityState.IsDeletedOrDetached()) continue;

            var validationErrors = new VerifierResultCollection();
            e.Verify(validationErrors);

            validationErrors =
                new VerifierResultCollection(entityAspect.ValidationErrors.Concat(validationErrors.Errors));
            validationErrors.Where(vr => !entityAspect.ValidationErrors.Contains(vr))
                .ForEach(entityAspect.ValidationErrors.Add);

            if (validationErrors.HasErrors)
                throw new EntityServerException(validationErrors.Select(v => v.Message).ToAggregateString("\n"),
                                                null,
                                                PersistenceOperation.Save, PersistenceFailure.Validation);
        }

        return true;
    }
}

Last edited Jan 2, 2012 at 12:50 AM by marcelgood, version 11

Comments

No comments yet.