Validation – Part 3 – Server-Side

Validation – Part 3 – Server-Side

<Update>
You can download the sample application from here. Sorry, it turned into more than just a demo of the validation stuff.
</Update>

So far we’ve built-up a small foundation for a custom validation framework in part 1, and then tied that to a jQuery plugin for our client-side validation in part 2. In this part we’ll look at doing server-side validation. Of the three parts, this is the simplest.

Validator

Most of the heavy lifting takes place in our Validator class. Before looking at it, we’ll make use of a simple ValidationError object to hold any errors:

public class ValidationError
{
    public string Field { get; private set; }
    public string Message { get; private set; }

    public ValidationError(string field)
    {
        Field = field;
    }

    public ValidationError(string field, string message)
    {
        Field = field;
        Message = message;
    }
}

And here’s the powerful Validator:

public interface IValidator
{
    bool Validate(object o, out ValidationError[] errors);
}

public class Validator : IValidator
{
    private readonly IRepository _repository;
    public Validator(IRepository repository)
    {
        _repository = repository;
    }
    
    public bool Validate(object o, out ValidationError[] e)
    {
        var errors = new List<ValidationError>(10);
        var propertyErrors = ValidateProperties(o);
        if (propertyErrors != null)
        {
            errors.AddRange(propertyErrors);
        }
        var customErrors = ValidateCustom(o);
        if (customErrors != null)
        {
            errors.AddRange(customErrors);
        }           
        e = errors.ToArray();
        return e.Length == 0;            
    }        

    private static ICollection<ValidationError> ValidateProperties(object o)
    {                        
        //todo
    }
    private ICollection<ValidationError> ValidateCustom(object o)
    {
        //todo
    }
}

All the Validate method does is take an object and merge any attribute-based errors with any custom-based errors. Here’s the implementation for ValidateProperties:

private static ICollection<ValidationError> ValidateProperties(object o)
{                        
    if (!ValidatorConfiguration.Rules.ContainsKey(o.GetType()))
    {
        return null;
    }
    var errors = new List<ValidationError>(10);
    foreach (var property in ValidatorConfiguration.Rules[o.GetType()].Properties)
    {
        var value = property.Property.GetValue(o, null);
        foreach (var validator in property.Validators)
        {
            if (validator.IsValid(o, value)) { continue; }
            errors.Add(new ValidationError(property.Property.Name));
            break;
        }
    }
    return errors;
}

We loop through each validation attribute of each property of our object (assuming any validation rules are configured for it). Notice that we don’t add a message to our ValidationError – that’s because those are already rendered on the client in the form of the “tip” – we’ll get back to that in a bit.

The ValidateCustom is even simpler:

private ICollection<ValidationError> ValidateCustom(object o)
{
    if (!(o is IValidate))
    {
        return null;
    }
    return ((IValidate) o).Validate(_repository);            
}

Here’s an example of what a custom Validate method might look like:

//our user clas
public virtual ValidationError[] Validate(IRepository repository)
{
    if (repository.Exists<User>(u => u.Email == Email))
    {
        return new[] {new ValidationError("Email", "This email is already registered")};
    }
    return null;
}

Notice that I pass around an IRepository. That’s just to show how you might pass infrastructure elements that your validators will need.

Back to the Client

You can now use the Validator from your WebForms or Controllers. The downloadable example shows a more proper (opinionated) MVC example, but without going into the necessary infrastructure, you might do something as simple as:

public class UserController : Controller
{
    private readonly IValidator _validator;

    public UserController(IValidator validator)
    {
        _validator = validator;            
    }

     //Everything about this action is ugly, check out the example for a better approach
    public ViewResult Register([Bind(Exclude="id")]User user)
    {
           ValidationError[] errors;
            if (!_validator.Validate(user, out errors))
            {
                ViewData["ValidationErrors"] = ToJson(errors);
                return View(user);
            }
            //todo Save the user;
            return View("RegistrationSuccessful");
    }

    private string ToJSon(ValidationError[] errors)
    {         
            var sb = new StringBuilder("init:{");
            Array.ForEach(errors, e => sb.AppendFormat("{0}:'{1}',", e.Field, e.Message.Replace("'", "\\'"));
            _validationErrors = sb.RemoveLast().Append("}").ToString();
            return _validationErrors;
    }
}

We’ve serialized our array of errors to JSON and stored them in our ViewData. We’ll modify our jQuery plugin to handle the errros. First though, we change our jQuery call:

$('#register').validate({<%=Html.RulesFor<User>() %>, <%=ViewData["ValidationErrors"]%>});    

The last change is to the initialize method, while we are hooking up each field’s blur event, we’ll also see if an init error exists within the options:

$fields.each(function(i, field)
{
    var $field = $(field);
    $field.blur(function()
    {
        v.validateField(this);
    });                          
    if (options.init[field.name] != null)                        
    {                            
        v.markAsInvalid($field, options.init[field.name] != '' ? options.init[field.name] : rules[field.name].tip);
    }                      
});

Conclusion

Folks, that’s how easy it is to do custom validation. Granted its quite a bit of code, but there’s nothing overly complex (except for maybe the reflection or jQuery plugin if you aren’t familiar with either). Do stay tuned as tomorrow I’ll make a sample application available for download which should help make all of this more useful.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

8 Responses to Validation – Part 3 – Server-Side

  1. karl says:

    @Bernhard:
    premature. I’m not trying to justify it, but List has an interesting growth algorithm. Most of the time it simply doubles in size. However, if it has a size of 0 (which it does if you don’t specify it), it jumps to 4 and then doubles.

    In this context, its a meaningless ram vs cpu trade-off.

  2. Bernhard Hofmann says:

    I’m wondering why the number ten appears in the line:

    var errors = new List(10);

    Is that premature optimisation, or just pessimism on your part? :P

  3. karl says:

    kbrowns:
    I’m probably too close to the code to feel your pain. In my mind that line returns a bunch of configuration validation rules based on a type. That might be enough to get you through the function. Granted you don’t know what a “validation rule” is, but if you need to know, you can go look inside the relevant code.

    I can’t imagine that:

    foreach(PropertyValidationInfo property in….) { }

    would be that much more meaningful to you? This is some pretty specialized infrastructure code. I don’t think explicit type names really does anything.

  4. kbrowns says:

    touche

    I haven’t touched a dynamic language in a very long time so I’m ignorant on the matter. Having said that, It seems to me that where a language begins and ends and where that language’s libraries begins is ever blurring. So much of what makes a language useful is it’s libraries that come with the platform, which automatically makes me really care about types from a readability standpoint. Dynamic, or Static, I don’t understand how anyone can understand what this is at face value:

    foreach (var property in ValidatorConfiguration.Rules[o.GetType()].Properties)
    {

    }

    My thought process goes like this:

    - Ok, I know what GetType is, that’s a System.Type
    - That’s getting passed into something called Rules
    - Rules is returning something…. but what?
    - Properties? Maybe an array of PropertyInfos?
    - Ok, it’s doing something to each of the property instances
    - Nope, not a PropertyInfo cuz it’s got something on it called Validators
    - What is Properties? I need to reread what’s above
    - Rinse and repeat

    When I’m in Visual Studio and have R# at my fingertips, I can usually get through it, but it’s still a fair amount of work trying to grok small pieces of code.

    I’m describing what an experience I’m having daily – not just on your blog of course. Does that just mean I’m not cut out for dynamic langunages? I definitely get the power dynamic languages offer, but my eyeballs bleed reading it – no matter how well factored because eventually something has to be returned from a function and when it does, my brain does a blue-screen. Maybe I just to approach the reading process differently.

    Sorry to ramble off topic… thanks again for the validation posts

  5. karl says:

    kbrowns:
    No, I don’t think it helps readability. I didn’t like var when they first announced it, but I’ve since become an addict and use it almost everywhere (I twitter about it every now and again). I think most people would agree with you that I use it excessively.

    However, this is normally the only way to do it in a dynamic language, and I’m not sure properly refactored dynamic code is any harder to read because of it, and I don’t see why C# code could be.

  6. kbrowns says:

    Solid post – thanks

    I have do ask… do you think the use of the var keyword makes this sample easier to read?

    private static ICollection ValidateProperties(object o)
    {
    if (!ValidatorConfiguration.Rules.ContainsKey(o.GetType()))
    {
    return null;
    }
    var errors = new List
    (10);
    foreach (var property in ValidatorConfiguration.Rules[o.GetType()].Properties)
    {
    var value = property.Property.GetValue(o, null);
    foreach (var validator in property.Validators)
    {
    if (validator.IsValid(o, value)) { continue; }
    errors.Add(new ValidationError(property.Property.Name));
    break;
    }
    }
    return errors;
    }

    I understand it because I’ve inadvertently memorized the System.Reflection namespace over the years.

  7. karl says:

    @Kazi:
    1 – I’d need to look at what’s available, but I’m not opposed to it.

    2 – Yes.

    3 – Yes, but I documented that and the example will have it corrected. I did it for simplicity sakes.

    4 – Again, all this stuff is cleaned up in the example. But I still use ViewData (magic string-use is greatly reduced though). Maybe I’m missing an advantage of ModelState, but it just seems like another container.

  8. Few concerns:

    1. All over the place you are hand coded the JSON construction, why not using a library or the built in JavaScriptSerializer?

    2. In the First Part the BaseValidatorAttribute attribute has a method ToJSon which returns a Dictionary, Is not it wrongly named?

    3. ToJson in controller is not a code smell? should not it belongs to an extension method of IEnumerable?

    4. Why you are abusing the ViewData. What is wrong with ModelState?