The information in this post was written for the ASP.NET AJAX 4.0 Preview 4, and is subject to change with future releases.

A new feature in the ASP.NET AJAX 4.0 client library is the Function.validateParameters() method. I say “new,” but it has really been there all along as a the private member Function._validateParams(). We all know that there is no such thing as public and private in JavaScript, but the accepted practice is that all members starting with an underscore (“_”) should be considered private and left untouched. You are free to call private member functions and access private member variables if you like, but doing so is bad for a number of reasons. First, it violates industry standard. Second, and most importantly, doing so is not supported by Microsoft. So if in a future release Microsoft suddenly decides to change the behavior of the private member to something unexpected, you won’t have anyone to blame but yourself.
As of Preview 4 of the ASP.NET AJAX 4.0 client library, the functionality has been exposed through the Function.validateParameters() method. I’m glad the folks at Microsoft have realized the value in making this feature public. Here’s how you can start using it today…
Function.validateParameters(parameters, expectedParameters, validateParameterCount)
parameters
The first argument is the list of the parameters that were actually passed to the JavaScript function. This can be easily accessed by calling the arguments variable, which is local to every function.
function doSomething(aString, aNumber) {
var e = Function.validateParameters(arguments, [
{ name: "aString", type: String },
{ name: "aNumber", type: Number }
], false);
if (e) throw e;
// do something...
}
expectedParameters
The second parameter is an array containing information about each expected parameter. There are several options you can use to specify what type of parameter is expected:
var e = Function.validateParameters(arguments, [
{
name: "name", // any string value
type: [expected type], // any native or custom JavaScript type
integer: [true|false],
domElement: [true|false],
mayBeNull: [true|false],
optional: [true|false],
elementType: [true|false],
elementDomElement: [true|false],
elementInteger: [true|false],
elementMayBeNull: [true|false]
}, ...]);
name: The name of the parameter. The name is not used in any validation, but is instead used for error reporting. If validation fails, the name value will be passed to the Error object returned from Function.validateParameters() to indicate which parameter was the culprit.
type: The data type of the parameter. This can be a native JavaScript type, an ASP.NET AJAX client library type, or your own custom type.
function sendMessage(message) {
var e = Function.validateParameters(arguments, [
{ name: "message", type: String }
], true);
if (e) throw e;
// send message...
}
sendMessage('This is a test message');
function saveCustomer(customer) {
var e = Function.validateParameters(arguments, [
{ name: "customer", type: MyApp.Entities.Customer}
], true);
if (e) throw e;
// save customer...
}
var customer = new MyApp.Entities.Customer();
saveCustomer(customer);
domElement: A boolean value indicating whether or not the parameter is a DOM element.
function updateContent(container) {
var e = Function.validateParameters(arguments, [
{ name: "container", domElement: true }
], true);
if (e) throw e;
// update content...
}
var divContainer = $get('container');
var nonExistingElement = $get('nothing'); // returns null
updateContent(divContainer);
updateContent(nonExistingElement); // throws Sys.ArgumentException
updateContent('test'); // throws Sys.ArgumentNullException
integer: A boolean value indicating whether or not the parameter is an integer. Only evaluated if the type option is set to Number.
function updateAge(age) {
var e = Function.validateParameters(arguments, [
{ name: "age", type: Number }],
true);
if (e) throw e;
// update age...
}
updateAge(23.78); // ok
updateAge(23); // ok
function updateAge(age) {
var e = Function.validateParameters(arguments, [
{ name: "age", type: Number, integer: true }],
true);
if (e) throw e;
// update age...
}
updateAge(23.78) // throws Sys.ArgumentOutOfRangeException
updateAge(23); // legal
mayBeNull: A boolean value indicating whether or not the parameter may be null.
function doSomething(aString) {
var e = Function.validateParameters(arguments, [
{ name: "aString", type: String, mayBeNull: true }],
true);
if (e) throw e;
// do something...
}
doSomething(''); // ok
doSomething(null); // ok
doSomething(); // throws Sys.ParameterCountException
optional: A boolean value indicating whether or not the parameter is optional.
function doSomething(aString) {
var e = Function.validateParameters(arguments, [
{ name: "aString", type: String, optional: true }],
true);
if (e) throw e;
// do something...
}
doSomething(''); // ok
doSomething(null); // throws Sys.ArgumentNullException
doSomething(); // ok
elementType: The data type expected for each element of an array parameter. This can be a native JavaScript type, an ASP.NET AJAX client library type, or your own custom type. Does not enforce any restriction on the array size.
function doSomething(anArray) {
var e = Function.validateParameters(arguments, [
{ name: "anArray", type: Array, elementType: String }],
true);
if (e) throw e;
// do something...
}
doSomething([]); // ok
doSomething(['test']); // ok
doSomething(['one', 'two']); // ok
doSomething(['one', 'two', 3]); // throws Sys.ArgumentTypeException
doSomething(); // throws Sys.ParameterCountException
elementDomElement: A boolean value indicating whether or not each element in the array parameter is a DOM element. Does not enforce any restriction on the array size.
function doSomething(anArray) {
var e = Function.validateParameters(arguments, [
{ name: "anArray", type: Array, elementDomElement: true }],
true);
if (e) throw e;
// do something...
}
doSomething([$get('container')]); // ok
doSomething(['test']); // throws Sys.ArgumentException
doSomething(); // throws Sys.ParameterCountException
elementInteger: A boolean value indicating whether or not each element in the array parameter is an integer. Only evaluated if the type option is set to Number. Does not enforce any restriction on the array size.
function doSomething(anArray) {
var e = Function.validateParameters(arguments, [
{ name: "anArray", type: Array, elementType: Number, elementInteger: true }],
true);
if (e) throw e;
// do something...
}
doSomething([]); // ok
doSomething([null]); // throws ArgumentNullException
doSomething([1, 2, 3]); // ok
doSomething(); // throws ParameterCountException
elementMayBeNull: A boolean value indicating whether or not each element in the array parameter may be null. Does not enforce any restriction on the array size.
function doSomething(anArray) {
var e = Function.validateParameters(arguments, [
{ name: "anArray", type: Array, elementMayBeNull: true }],
true);
if (e) throw e;
// do something...
}
doSomething([]); // ok
doSomething([null, '']); // ok
doSomething(['test', null, 'test']); // ok
doSomething(); // throws Sys.ParameterCountException
parameterArray: A boolean value indicating whether or not the parameter is a variable-length array. This option is helpful when you want to define a function with a required set of parameters and a variable number of trailing parameters. A good example is the ASP.NET AJAX client library’s String.format():
String.format = function String$format(format, args) {
var e = Function._validateParams(arguments, [
{name: "format", type: String},
{name: "args", mayBeNull: true, parameterArray: true}
]);
if (e) throw e;
return String._toFormattedString(false, arguments);
}
It expects a format parameter or type String, and then a variable number of arguments.
var name = "Kevin", age = 28;
var formattedValue = String.format("Name: {0}, Age: {1}", name, age);
There are some peculiarities that you should be aware of when using several mutually exclusive parameter options (domElement, integer, etc) at the same time. Specifically, there is an order of precedence when evaluating the parameter rules and certain combinations of options may cause unexpected results. However, those details will have to wait for another post.
validateParameterCount
The third argument to Function.validateParameters() indicates whether or not to explicitly validate the parameter count. JavaScript allows you to pass in a different number of parameters than expected by a function.
function doSomething(aString, aNumber) {
// do something...
}
// both of the following function calls are legal
doSomething('test'); // aString = 'test', aNumber = undefined
doSomething('test', 1, 2, 3); // aString = 'test', aNumber = 1
Passing fewer parameters than expected by a JavaScript function results in the extra parameters being undefined. Passing more parameters than expected is also legal, but the extra parameter values are only accessible by referencing the proper index in the local arguments variable.
Using the validateParameterCount option, you can ensure that the correct number of parameters is present.
function doSomething(aString) {
var e = Function.validateParameters(arguments, [{ name: "aString" }], true);
if (e) throw e;
// do something...
}
doSomething('test'); // ok
doSomething(25); // ok
doSomething(); // throws a Sys.ParameterCountException
The first two calls to doSomething() are perfectly legal. Since no parameter type was specified, the only validation that occurs is the parameter count. The third call will cause Function.validateParameters() to return an Error.parameterCount exception, which will be thrown by the calling function.
Since the ASP.NET AJAX client library validates the parameters passed in to Function.validateParameters(), you cannot omit the first two. However, the third is optional and will default to true if unspecified.
It is important to note that when using the validateParameterCount option in conjunction with the parameterArray option, the enforced minimum number of parameters will be the number of parameters preceding the one with the parameterArray option in the expectedParameters array.
// requires a minimum of 2 parameters, no maximum
function doSomething(aString, aNumber, params) {
var e = Function.validateParameters(arguments, [
{ name: "aString", type: String },
{ name: "aNumber", type: Number },
{ name: "params", parameterArray: true }
], true);
if (e) throw e;
// do something...
}
// requires a minimum of 1 parameter, no maximum
function doSomethingElse(aString, params) {
var e = Function.validateParameters(arguments, [
{ name: "aString", type: String },
{ name: "params", parameterArray: true }
], true);
if (e) throw e;
// do something...
}
doSomething('test'); // throws a Sys.ParameterCountException
doSomething('test', 123); // ok
doSomething('test', 123, 'testing', 123); // ok
doSomething(); // throws a Sys.ParameterCountException
doSomethingElse('test'); // ok
doSomethingElse('test', 123, 123); // ok
Wrap up
Due to its dynamic nature and language-specific peculiarities, type-checking in JavaScript is usually a cumbersome task. Fortunately, the folks at Microsoft have abstracted those details away into a tidy little function call, making it easier than ever to enforce type safety on our functions. Since it is used to perform type-checking throughout the entire ASP.NETAJAX client library, I think it is safe to assume that Function.validateParameters() performs fairly well. However, I haven’t done any performance testing myself so I recommend testing it in your own applications before using it extensively.
