Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Including custom client-side validations in your ASP.NET MVC app

0.00/5 (No votes)
4 Aug 2010CPOL3 min read 9.7K  
Demonstrates how a self-written validation can be incorporated into a web page (using a bit of JavaScript) and how this can be mapped to a custom validation on the domain side

This post is a follow-up on my series about validating business objects throughout different layers of a software system - domain, persistence, and (ASP.NET MVC) GUI. It demonstrates how a self-written validation can be incorporated into a web page (using a bit of JavaScript) and how this can be mapped to a custom validation on the domain side.

A Short Recap

In the first part of the above mentioned series, we developed a simple, custom validation aspect that checks if a value really is a member of a specified enumeration. Here's the typical usage for this EnumValue attribute:

C#
[EnumValue(typeof(Gender))]
public Gender Gender
{
    get { return this.gender; }
    set { this.gender = value; }
}

And this is the validation method that gets called in the end:

C#
if (!Enum.IsDefined(EnumType, @value))
{
    throw new ValidationException(string.Format(
        "'{0}' is not a valid value for enumerations of type '{1}'.",
        @value,
        EnumType.FullName));
}

In the third part of the series then, I demonstrated how server-side validations (using the PostSharp-based ValidationAspects framework) can be "translated" to client-side validations that reside in ASP.NET MVC pages, using the xVal framework to do the mapping.

Using a Custom xVal Rule Together with a Custom JScript Function

The aforementioned post showed only the mapping for the built-in aspects of the VA library. To do the same thing for our custom EnumValue attribute, we must declare another xVal RulesProvider, which is specific to this attribute, and provides a set of xVal rules that correspond to the EnumValue attribute. The xVal framework provides the PropertyAttributeRuleProviderBase<TAttribute> base class for this purpose, all we have to do is to provide an implementation of the MakeValidationRulesFromAttribute enumeration method for the specific attribute. Here's the declaration for the EnumValue validation aspect:

C#
public class EnumValueRulesProvider : 
	PropertyAttributeRuleProviderBase<EnumValueAttribute>
{
    protected override IEnumerable<Rule> 
	MakeValidationRulesFromAttribute(EnumValueAttribute attribute)
    {
        yield return new RequiredRule(); // field must not be empty
 
        const string jsMethodName = "isOneOf";
        var parameters = new { allowedValues = Enum.GetNames(attribute.EnumType),
                               secretValue = "EASTER_EGG" };
        string errorMessage = string.Format
			("Not a valid value for the '{0}' enumeration.",
                                            attribute.EnumType.Name);
 
        yield return new CustomRule
	(jsMethodName, parameters, errorMessage); 	// checks actual value 
						// against enum values
    }
 
} // class EnumValueRulesProvider

As you can see, the EnumValue validation aspect is represented by two xVal rules on the client side: The first one (xVal's RequiredRule) makes sure that there actually is some value provided on the web form, whereas the second one is a bit more interesting: An instance of the CustomRule class is used to reference a self-written JScript function ("isOneOf()") along with the required parameters ("allowedValues" and "secretValue") and the error message that should appear in case of validation failures. The function arguments must be provided in the form of an anonymous type, with the individual items as its members.

And of course, our new RulesProvider must be registered with the application on startup. Hence, the following line must be added to the Application_Start() event handler in Global.asax.cs:

C#
xVal.ActiveRuleProviders.Providers.Add(new EnumValueRulesProvider());

Now on to the client side. A JScript function, that is referenced in an xVal CustomRule class, must take three parameters:

  • value: The value to validate (usually the content of some sort of HTML input element)
  • element: The HTML input element itself
  • params: An array that contains the CustomRule-provided method arguments

The function should return true or false, depending on the result of the validation operation. The above referenced isOneOf() function could look like this:

C#
// Return true if 'value' matches one of the values in 'params.allowedValues' 
// (case insensitive).
// Used in a custom xVal rule to map the 'EnumValue' VA aspect.
//
// Parameters
// ----------
//
// params.allowedValues
// Comma-separated list of possible values for the 'value' param
// params.secretValue
// A 'secret' string (for demo purposes)
function isOneOf(value, element, params) {
    if (params.secretValue == value) {
        alert("Congratulations!\nYou have found the secret value 
		(but it won't validate...).");
    }
    var possibleValues = params.allowedValues
                               .toString()
                               .toLowerCase()
                               .split(",");
    var valueToCheck = value.toString().toLowerCase();
    for (i = 0; i < possibleValues.length; i++) {
        if (possibleValues[i] == valueToCheck) {
            return true;
        }
    }
    return false;
}

That's it! Quite simple and straightforward. As a result, we will have a client-side validation similar to this:

NotAGender

...or this, respectively:

EmptyGender

I could think of many possible use cases for this technique of mapping C# validations (server-side) to JScript functions (client-side)...

<iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&Task=Get&PageID=31016&SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No> <script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&Task=Get&Browser=NETSCAPE4&NoCache=True&PageID=31016&SiteID=1"></script> <noscript> </noscript> </iframe>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)