Skip to main content

An Asp.Net Validation Framework

I've been working on different ways to implement a validation framework that would really cut down on the code. It  had to be reusable and testable. I also didn't want to swap writing one bunch of repetitive code for another.

I'd looked at CSLA from Rockford Lhotka. I liked the way he implemented broken rules but CSLA had a lot of stuff for multiple undo's that was not relevant to my apps. I then used some of ScottGu's stuff for LINQ to SQL and begin using validation methods that threw exceptions. Reusable and custom exceptions made this very testable but I was still writing a bunch of repetitive code.

Microsoft's Enterprise Library has a Validation Block that was interesting but really seemed to be overkill.  I did like the declarative nature though and then found this from Imar Spaanjaars. That was more what I was looking for and I could see where I could make some changes.

First change was in the naming. NotNullOrEmptyAttribute became RequiredAttribute and ValidSsnAttribute became SsnAttribute. This seemed to work better for me.

Next was removing the localization. I've never had to write an app for anything but English. I know, next week I'll get one. That's ok, I left some places to hook in if I need to.

The largest change was to how I handle messages. I created a number of attributes to handle common elements like proper names, SSN, phone numbers, etc  (more on these in a later post) and I wanted to be able to do something like below.

[Required(DisplayName="SSN")]
[Ssn]
public string Ssn { get; set; }

Notice on the Ssn attribute there is no message property set. I have used pretty much the same error message for bad SSN's since I can remember. Why do I need to type a message on SSN element? I don't!

Everything starts with the ValidationAttribute class and all custom validation attributes will inherit from this class. Let's look at it.

/// <summary>
/// Base class for validation attributes.
/// </summary>
public abstract class ValidationAttribute
    : System.Attribute
{
    /// <summary>
    /// Initializes a new instance of the ValidationAttribute class.
    /// </summary>
    public ValidationAttribute()
    {
        this.DisplayName = string.Empty;
    }

    /// <summary>
    /// Gets or sets the BrokenRule with the error message.
    /// </summary>
    public BrokenRule Rule { get; set; }

    /// <summary>
    /// Gets or sets the name to be displayed for the element.
    /// </summary>
    public string DisplayName { get; set; }

    /// <summary>
    /// Gets or sets the error message.
    /// </summary>
    public string Message { get; set; }

    /// <summary>
    /// Indicates if the property is valid according to the attribute.
    /// </summary>
    /// <param name="item">The value of the property.</param>
    /// <param name="propName">The name of the property.</param>
    /// <returns>True if the property passes the validation rule, otherwise false.</returns>
    public abstract bool IsValid(object item, string propName);
}

There are three properties and one virtual method. Rule which is of type BrokenRule (more on this in a moment. DisplayName which holds the friendly name of the element. Notice how DisplayName is set to string.Empty in the constructor. Finally, we use Message to customize messages when needed.

The IsValid method checks to see if the element is valid (based on validation code in the subclasses). It accepts the value and name of the property as arguments. The value comes through as an object so that we can apply the attribute to different types. The name is passed because there is no link between the attribute and it's property.

Now we need a class that will actually validate something. The most common validation is required elements so we'll start with the RequiredAttribute.

/// <summary>
/// Attribute for validating that a value is not empty or null.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class RequiredAttribute
    : ValidationAttribute
{
    /// <summary>
    /// Initializes a new instance of the RequiredAttribute class.
    /// </summary>
    public RequiredAttribute()
    {
        DisplayName = "value";
    }
    
    /// <summary>
    /// Validates that the string is not empty or null.
    /// </summary>
    /// <param name="item">The string to be validated.</param>
    /// <param name="propName">The name of the invalid property.</param>
    /// <returns>True if the string has a value and is not empty, otherwise false.</returns>
    public override bool IsValid(object item, string propName)
    {
        Rule = new Rules.RequiredRule(propName, DisplayName);
        if (!Message.IsEmpty())
        {
            Rule.Message = Message;
        }

        if (item is string)
        {
            return !string.IsNullOrEmpty(item as string);
        }

        if (item is DateTime)
        {
            if (item == null)
            {
                return false;
            }

            if (Convert.ToDateTime(item) == DateTime.MinValue)
            {
                return false;
            }

            return true;
        }

        if (item is int)
        {
            if (Convert.ToInt32(item) == 0)
            {
                return false;
            }

            return true;
        }

        return item != null;
    }
}

The DisplayName is set to "value" by default but will get overridden if set. Otherwise, the only code is to check if the property actually has a value. Strings, DateTime and ints are all checked. In case you're wondering, IsEmpty is an extension method I wrote that checks if a string is null or empty.

What the Rule property? Well, we create an instance of the RequiredRule and pass the property and display names. RequiredRule is a subclass of BrokenRule with a default message. Here's the code for both.

/// <summary>
/// Simple representation of a broken business rule.
/// </summary>
public class BrokenRule
{
    /// <summary>
    /// Initializes a new instance of the BrokenRule class.
    /// </summary>
    public BrokenRule()
    {
    }

    /// <summary>
    /// Initializes a new instance of the BrokenRule class.
    /// </summary>
    /// <param name="propName">The name of the property that was invalid.</param>
    public BrokenRule(string propName)
    {
        this.PropertyName = propName;
    }

    /// <summary>
    /// Initializes a new instance of the BrokenRule class.
    /// </summary>
    /// <param name="propName">The name of the property that was invalid.</param>
    /// <param name="msg">The error message.</param>
    public BrokenRule(string propName, string msg)
    {
        this.PropertyName = propName;
        this.Message = msg;
    }

    /// <summary>
    /// Gets or sets the name of the property that was invalid.
    /// </summary>
    public string PropertyName { get; set; }

    /// <summary>
    /// Gets or sets the error message.
    /// </summary>
    public string Message { get; set; }
}

/// <summary>
/// Class to represent a broken required field rule.
/// </summary>
public class RequiredRule
    : BrokenRule
{
    /// <summary>
    /// Initializes a new instance of the RequiredRule class.
    /// </summary>
    /// <param name="propName">The name of the property that was invalid.</param>
    /// <param name="dispName">The name to be displayed for the element.</param>
    public RequiredRule(string propName, string dispName)
        : base(propName, string.Format(RuleMessages.RequiredMessage,
        dispName == string.Empty ? propName : dispName))
    {
    }
}

BrokenRule has the property name and the message. RequiredRule simply formats the constant RequiredMessage  with the DisplayName  (or property name if there isn't a DisplayName) and passes it to the base constructor.

You might be asking why not simply use a factory method to get the default message instead of a custom type? The answer is that this allows me to test for specific attributes without having to check all the different messages using Assert.IsInstanceOf.

Assert.IsInstanceOfType(testMock.BrokenRules[0], typeof(RequiredRule));

Assert.IsInstanceOfType(testMock.BrokenRules[0], typeof(SsnRule));
Now my unit tests can check if the Required and Ssn attributes were applied. Testability was just as important as getting rid of the repetitive code.

Next, we'll look at how to get your objects to use these attributes.

Comments

Popular posts from this blog

Migrating Legacy Apps to the New SimpleMembership Provider

Asp.Net MVC4 uses the new SimpleMembership provider, changes the table structure and adds a new hashing algorithm. The reasons for the changes can be found in this article by Jon Galloway. This article shows how to migrate your existing apps to the new provider.I’m assuming that you stored your passwords in the unrecoverable SHA-1 format. If you didn’t, then you’ll have to change a couple of things. All of my apps are done this way so… I’m also assuming that you have created the basic skeleton of the new app and ran it once so the correct tables will be created.First, we’ll look at the new tables. Previously, we had all of those aspnet_xxxxxx tables. Here’s the new ones.UserProfileContains all of the elements relevant to the user. This is a combination of the aspnet_Users table and the aspnet_Profiles table.webpages_MembershipStores the password info when not using OAuth, Live, Facebook, etc. This table is somewhat of a match to the aspnet_Membership table.webpages_OAuthMembershipStor…

JavaScript function to automatically add slashes to date

In converting an old Windows app to a browser app, the user wanted to be able to enter dates without the slashes. Here's a simple jscript: 1:// Function to convert short date string (MMddyy) 2:// or (MMddyyyy) to a date string (mm/dd/yyyy). 3:// txtBox is the actual textbox control 4:// with the value to be processed. 5:function FixShortDate(txtBox) { 6:if (txtBox == null) { 7:return'' } 8: 9:var re = new RegExp(/(\d{6})(\d{2})?/); 10: 11:if (re.test(txtBox.value)) 12: { 13:if (txtBox.value.length == 8) { 14: txtBox.value = txtBox.value.substring(0, 2) + '/' + txtBox.value.substring(2, 4) + '/' + txtBox.value.substring(4, 8) 15: } 16: 17:if (txtBox.value.length == 6) { 18:if (txtBox.value.substring(4, 6) < 20)

Get Asp.Net Profile properties from Sql

Ever wanted to include the profile information from an Asp.Net profile in a query? It’s not that hard once you understand the structure. I’ve written a little function that does all the work. Note: I’m using Sql Server as my repository.

First we need to understand how the profile data is stored. Looking at the aspnet_Profile table, we can see that it stores the information in two columns: PropertyNames and PropertyValuesString.

Looking at PropertyNames we can see that it has a basic structure of Property Name, Data Type, Starting Position and Length. For example, in the string “FirstName:S:0:4:Phone:S:4:10:LastName:S:14:5:” we can see that FirstName is of type string, starts at position 0 and has a length of 4. Notice the zero base for the starting position, we need to correct for that in our function. This means in the PropertyValuesString “John2175551212Smith”, we would start with the first position and proceed 4 characters to get the name.

You might be thinking …