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:
[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:
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:
public class EnumValueRulesProvider :
PropertyAttributeRuleProviderBase<EnumValueAttribute>
{
protected override IEnumerable<Rule>
MakeValidationRulesFromAttribute(EnumValueAttribute attribute)
{
yield return new RequiredRule();
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);
}
}
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:
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:
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:
...or this, respectively:
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>
CodeProject