Complex custom validation with ASP.NET MVC, jQuery Unobtrusive Validation & KnockoutJS

When developing ASP.NET line of business web applications, one very common requirement is to perform validation of user input.  In a modern, responsive web application this validation is expected to be performed on the client-side, using JavaScript, as well as on the server-side using standard C# code.  ASP.NET MVC ships with jQuery as a standard library and also includes a validation library called jQuery Unobtrusive Validation (latest repository is here), which is an open-source, Microsoft specific add-on to the jQuery Validation plugin.

It's very easy easy to enable jQuery Unobtrusive Validation in an ASP.NET MVC 3+ application.  You simply add the following settings into your web.config:

<configuration>
    <appSettings>
        <add key="ClientValidationEnabled" value="true"/>
        <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
    </appSettings>
</configuration>

Now, out of the box, jQuery unobtrusive validation allows you to simply decorate your C# model class properties with attributes from the System.ComponentModel.DataAnnotations namespace, like so:

public class MyViewModel
{
	[Required]
	[MaxLength(250)]
	public string Name { get; set; }

	[MaxLength(1000)]
	public string Description { get; set; }
}

Here, we're saying that the Name property is both required and has a maximum length of 250 characters.  The Description property isn't required, but does have a maximum length of 1000 characters if it's supplied.

jQuery Unobtrusive Validation has out-of-the-box implementations of a number of Data Annotation validation attributes, which all derive from the ValidationAttribute class.  Some of these are:

  • Required (ensures the input element is provided and not left empty)
  • MinLength (ensures the text-based input element has a minimum amount of characters entered)
  • MaxLength (ensures the text-based input element has a no more than a maximum amount of characters entered)
  • Range (ensures that the numeric-based input element is within a certain range of values)
  • RegularExpression (ensures that the input elements value conforms to a provided regular expression)

Note that there are more attributes available within the System.ComponentModel.DataAnnotations namespace, however, not all of them have a default implementation within jQuery Unobtrusive Validation.

When the View Model is rendered out to the web page, ASP.NET MVC and jQuery Unobtrusive Validation will render HTML mark-up similar to the following:

<input  id="myField" data-val="true"
		data-val-maxlength="The field Name must not be longer than 250 characters."
		data-val-maxlength-max="250"
		data-val-required="The Name field is required."
		placeholder="Enter Name..." 
		type="text"
		value="">
<span data-valmsg-for="myField" data-valmsg-replace="true"></span>

Here we can see the various data-* attributes being rendered on the input element.  The Unobtrusive Validation JavaScript looks for all elements that are decorated with data-val-* attributes and uses them to perform client-side validation complete with showing/hiding relevant error messages, for example:

Now, this is all well and good when dealing with the most basic of validation requirements, however, there is frequently a need for validation to encompass far more elaborate business rules and complex logic.  Such logic often involves performing certain validation operations not just on a single granular property, but on multiple properties of the model.  It is, unfortunately, at this point that the out-of-the-box jQuery Unobtrusive Validation falls short and we must rely on custom developed validation for this.

Moreover, jQuery Unobtrusive Validation is largely geared towards rendering a web page / form that contains a set amount of input elements when first loaded.  Again, lots of line of business applications frequently have "dynamic" elements added to the form at run-time.  This is most often used when the user of the application is expected to build up a "table" of data, like so:

In the animation above, we can see that new rows are able to be added to the "Rates" table.  We can also see that there's validation on each row of the table, whereby the Owner Writer Share and Net Publisher Share text boxes, which each contain a numeric percentage value, have to add up to 100.

Such user interfaces and forms are not uncommon in a line of business application, but the validation required for this goes way beyond that which the jQuery Unobtrusive Validation offers out of the box.  Developing custom validation for such a form often requires juggling a number of frameworks or libraries and setting up and configuring things "just right" to ensure everything works as expected.  In order to make sense of the various pieces that need to fit together, we'll take a look at each of them one by one.

Creating our custom validator

The first part requires us to create our custom validator.  This requires two steps.  The first step is to create the C# class which is a custom attribute and implements the server-side validation logic, and the second step is to implement a JavaScript function which "mimics" the C# class and provides the same validation logic to the client browser.

Server-side implementation

The C# class is a custom attribute deriving from ValidationAttribute class (for server-side implementation) and also implementing the IClientValidatable interface (in order to "expose" this custom validation logic to the client-side validation framework).   Here's our C# class:

    [AttributeUsage(AttributeTargets.Property)]
    public class MustAddUpToAttribute : ValidationAttribute, IClientValidatable
    {
        public string OtherPropertyName { get; private set; }
        public double Amount { get; private set; }

        public MustAddUpToAttribute(double amount, string otherPropertyName, string errorMessage) : base(errorMessage)
        {
            Amount = amount;
            OtherPropertyName = otherPropertyName;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            double thisValue;
            double otherValue;
            PropertyInfo propertyInfo;
            try
            {
                thisValue = Convert.ToDouble(value);
            }
            catch(Exception ex)
            {
                throw new InvalidOperationException("Property Type is not numeric", ex);
            }
            try
            {
                propertyInfo = validationContext.ObjectType.GetProperty(OtherPropertyName);
            }
            catch (ArgumentException ex)
            {
                throw new InvalidOperationException("Other property not found", ex);
            }
            try
            {
                otherValue = Convert.ToDouble(propertyInfo.GetValue(validationContext.ObjectInstance, null));
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Other property type is not numeric", ex);
            }
            var sumOfValues = thisValue + otherValue;
            return NumericHelpers.NearlyEqual(sumOfValues, Amount, double.Epsilon) ? ValidationResult.Success : new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }

        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessageString, name, OtherPropertyName);
        }
        
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = FormatErrorMessage(metadata.DisplayName),
                ValidationType = "mustaddupto"
            };
            rule.ValidationParameters.Add("otherpropertyname", OtherPropertyName);
            rule.ValidationParameters.Add("amount", Amount);
            yield return rule;
        }
    }

(Note that this class relies on a "NumericHelper" to determine near equality - see here for the implementation).

Also note that the .NET Framework provides an IValidateableObject interface, which isn't used here.  The IValidateableObject interface is used for model-level validation - i.e. ensuring an entire object is valid, rather than one or two properties.  Moreover, the IValidateableObject can only be used server-side with no client-side equivalent (client-side model validation must be performed and managed with bespoke JavaScript functions), therefore, it's often unused.

Our C# class takes three constructor parameters, the amount that the calculation must add up to, the name of the "other property" that we'll get the value from to add to the value of the property decorated with the attribute and an optional error message.  The custom attribute is used similar to this:

public class Rate
{
	[Required]
	public float OwnerWriterShare { get; set; }

	[Required]
	[MustAddUpTo(100, "OwnerWriterShare", "Owner Writer Share and Net Publisher Share must add up to 100.")]
	public float NetPublisherShare { get; set; }
}

Note how we use a string based reference to the "OwnerWriterShare" property name to tell the MustAddUpTo attribute that we're getting the value of the NetPublisherShare property (the property to which the attribute is applied) and then to get the value of the OwnerWriterShare property, add them together and determine if the total adds up to the total we require - the first parameter to the MustAddUpTo attribute. Also note that the validation is using both the OwnerWriterShare and NetPublisherShare properties, but the attribute itself is only applied to the NetPublisherShare property.  This ensures we're not "doubling up" by effectively having the same validation on both properties which would result in two copies of the same error message on the client.

So, this C# class gives us our server-side implementation, and includes the GetClientValidationRules method from the IClientValidatable interface.  The implementation of this method requires returning a ModelClientValidationRule object with the relevant properties set.  The ModelClientValidationRule effectively tells the jQuery Unobtrusive Validation framework which client-side implementation it should use along with the relevant parameters required to perform the validation.  We'll see the implementation shortly, but the main code line here is:

ValidationType = "mustaddupto"

The value of ValidationType must always be lower case, and will be the name of our JavaScript function that will implement the client-side validation logic.

Client-side implementation

Having written our C# server-side class, we now must implement the same validation logic on the client-side, which means writing JavaScript.  The JavaScript function name will be mustaddupto.  Here's the JavaScript code that implements our MustAddUpTo validator:

// ================================================================================================
// MustAddUpToAttribute
// ================================================================================================
$.validator.addMethod("mustaddupto", function (value, element, params) {
    // Get the value of the element that the validation is assigned to and
    // the value of the "other" element that we're comparing against.
    var thisValue = value;
    var otherValue = $('#' + params.otherpropertyname).val();
    var amount = params.amount;

    // If either this or the other value is null or "empty" simply return true
    // as we can't perform validation.  Other validation can assert not null/emptiness.
    if (thisValue == null || thisValue.length === 0) {
        return true;
    }
    if (otherValue == null || otherValue.length === 0) {
        return true;
    }

    // Check we're dealing with numbers.
    if ($.isNumeric(value) && $.isNumeric(value)) {
        var thisValueNumber = parseFloat(thisValue);
        var otherValueNumber = parseFloat(otherValue);
        var sumTotal = thisValueNumber + otherValueNumber;
        return nearlyEqual(sumTotal, amount);
    }

    // If we get here, we're dealing with a data type that we don't recognise
    // and can't process, so let the validation pass.
    return true;
});

$.validator.unobtrusive.adapters.add("mustaddupto", ["otherpropertyname", "amount"], function (options) {
    options.rules["mustaddupto"] = options.params;
    options.messages["mustaddupto"] = options.message;
});


// Supporting functions
function nearlyEqual(a, b) {
    if (a == b) return true;
    var diff = Math.abs(a - b);
    if (diff < 4.94065645841247E-320) return true;
    a = Math.abs(a);
    b = Math.abs(b);
    var smallest = (b < a) ? b : a;
    return diff < smallest * 1e-12;
}
// ================================================================================================

The bulk of the function is plain old vanilla JavaScript, but let's examine the first few lines of each block of code in more detail as they're the most interesting parts.  Firstly, we use the addMethod method of the validator object that's attached to the jQuery object in order to create and add our validation method to the jQuery Validation framework.  Note that this isn't the Microsoft-specific jQuery Unobtrusive Validation framework, just the jQuery Validation framework, which is the underlying framework for Microsoft's Unobtrusive Validation framework.  Once we've added our validation method to the jQuery Validation Framework, we'll hook it up to the Unobtrusive Validation library too by adding an "adapter" to the unobtrusive object (this is the line that begins $.validator.unobtrusive.adapters.add).  Firstly, we pass in the name first ("mustaddupto" - this the same name for the ValidationType property of the ModelClientValidationRule that we expose from our server-side implementation) and then a function which takes 3 arguments, value, element and params.  The value parameter is the value of the "property" (or rather element since this is client-side) to which the validation is attached - it's the same as the server-side model property that has the attribute on it.  The element parameter is the actual element that has the validation applied to it.  In our case here, we're only interested in the value itself as the framework will take care of visually highlighting the correct web page element that fails validation, so we don't need to concern ourselves with it here.  What we DO need, though, is the "other" element that we'll need to grab the value of in order to add the two values together.  That's passed in the params object, which is the same object as exposed by the ModelClientValidationRule from the server.  So, the JavaScript params object used in these lines:

var otherValue = $('#' + params.otherpropertyname).val();
var amount = params.amount;

has come from this section of the server-side code:

rule.ValidationParameters.Add("otherpropertyname", OtherPropertyName);
rule.ValidationParameters.Add("amount", Amount);

After having set up and registered our validation function with the jQuery Validation library, we then need to also tell the jQuery Unobtrusive Validation framework all about it's existence too.   We do this with this section of the JavaScript code:

$.validator.unobtrusive.adapters.add("mustaddupto", ["otherpropertyname", "amount"], function (options) {
    options.rules["mustaddupto"] = options.params;
    options.messages["mustaddupto"] = options.message;
});

The jQuery Unobtrusive Validation library has a collection of "adapters" which allow us to register (add) our jQuery Validation method to be used by the unobtrusive validation framework.  Again, we can see that the key parts of this are the name ("mustaddupto") - which is the same as the main JavaScript function name and the name exposed from the server, as well as an array of the string param names ("otherpropertyname" and "amount").

With the C# class written and the attribute applied to our Model class, and the JavaScript function written and registered with both the jQuery Validation and jQuery Unobtrusive Validation libraries, we can move on to the next step...

Adding dynamic elements to the page

In order to dynamically add new elements to a web page without requiring a full page reload, we will be required to use JavaScript or some JavaScript-based framework in order to add elements into the page DOM after the page is initially rendered.  One such framework that actually makes this kind of thing a lot easier to manage is KnockoutJS.  Although it's beyond the scope of this post to go into detail on KnockoutJS, it's sufficient to say that Knockout takes a JSON view model representing your form data and deals with the two-way binding, rendering and updating of both existing and new page elements with the underlying data.  This makes it very easy to dynamically add new elements onto a form, for example, adding new rows to a table of data.

We can expose our server generated viewmodel to the client-side JavaScript with a single line like this:

var koViewModel = ko.mapping.fromJS(@Html.Raw(JsonConvert.SerializeObject(Model)));

The code above uses the Knockout Mapping plugin to take our serialized Model and convert it into a Knockout view model, complete with the required observables to facilitate two-way data binding.  Knockout can then work by "binding" values from the underlying view model to page elements that are decorated with appropriate data-bind attributes, such as this:

<input data-bind="value: MyViewModel.OwnerWriterShare" />

The data-bind attribute tells Knockout to bind the value of the input element to the value of the OwnerWriterShare property of the JSON object, MyViewModel.  This binding is two-way, so changes to the model's value will have Knockout updating the input element, and changes to the input element will have knockout updating the underlying model's value.

This is fine for existing page elements, but Knockout also makes it easy to bind to an array within the underlying JSON model.  This means that as new elements are added to the array, entirely new sets of page elements are created (or destroyed) as the array grows or shrinks.  So, if we have this JSON view model:

{
	"MyViewModel" : {
		"Rates" : [{
				"OwnerWriterShare" : "50",
				"NetPublisherShare" : "50"
			}, {
				"OwnerWriterShare" : "60",
				"NetPublisherShare" : "40"
			}
		]
	}
}

And the following definition of a table within our page markup:

<table>
	<tbody data-bind="foreach: MyViewModel.Rates">
		<tr>
			<td><input data-bind="value: $data.OwnerWriterShare" /></td>
			<td><input data-bind="value: $data.NetPublisherShare" /></td>
		</tr>    
	</tbody>
</table>

Knockout will repeat the contents of the tbody for each element in the MyViewModel.Rates array due to the foreach: binding.  This is great for building up our additional <tr> table rows dynamically, with each element in each row bound to the correct underlying JSON property, managed by KnockoutJS, thanks to the Knockout data-bind attribute.  Allowing users to add a new row to a table is as simple as adding a small amount of JavaScript that simply adds a new element to the underlying view model array, and the Knockout foreach binding will deal with creating the necessary additional page elements.  However, we have further work to do in order to add our validation to the dynamically generated elements, and this involves specifying additional data-* attributes needed for the validation to work, and for that, we'll also require Knockout's help...

Adding validation to dynamically added elements

So, we've got our custom validation functions written and we've wired up Knockout to help generate our page elements and performing the necessary two-way data binding, but now we need to add some additional attributes to our generated markup to ensure that the required validation is added to these elements.

Unobtrusive validation data attributes

Unobtrusive validation works by decorating our elements with data-val-* attributes.  These attributes are ignored by the browser, but JavaScript can read them and the values they contain in order to do all manner of interesting things.  In looking at our rendered input element from earlier:

<input data-bind="value: MyViewModel.Name"
        data-val="true"
        data-val-maxlength="The field Name must not be longer than 250 characters."
        data-val-maxlength-max="250"
        data-val-required="The Name field is required."
        id="MyViewModel_Name"
        name="MyViewModel.Name"
        placeholder="Enter Name..."
        type="text"
        value="">

We can see that as well as the Knockout specific data-bind attribute, we also have a number of attributes the start data-val.  It's these attributes that control the application of validation for the element by the jQuery Unobtrusive Validation library.  There's a data-val attribute that contains a boolean value to indicate whether this element is subject to validation.  Then, we have a number of other attributes starting with data-val that control the actual validation itself.  We'll have an attribute named data-val-VALIDATORNAME for each validation function that is applied to the element, and if that validation required further parameters, these are provided by additional parameters with the required parameter name in the attribute name.  So, for example, the data-val-maxlength attribute contains the error message to be shown when this validation fails and the data-val-maxlength-max attribute holds the value for the maximum length allowed.  We also have a data-val-required attribute that contains the error message for failure of that particular validation, however, there's no further attributes for that validation as no further parameters are required.

Now, when we're rendering known elements from a server-side view model, we can use ASP.NET MVC's Html Helpers to ensure that all of the these necessary attributes are applied to the rendered elements for us, so we will frequently see code such as this in a Razor view:

<div class="form-group">
	@Html.LabelFor(m => m.Username, new { @class = "control-label col-md-3" })
	<div class="col-md-9">
		@Html.TextBoxFor(m => m.Username, new { @class = "form-control", @placeholder = "Enter Username..." })
		@Html.ValidationMessageFor(m => m.Username, string.Empty, new { @class = "text-danger" })
	</div>
</div>

The @Html.TextBoxFor and @Html.ValidationMessageFor directives are aware of any validation attributes applied to the server-side model and will ensure that the relevant data-val attributes are applied to the rendered output (the ValidationMessageFor directive ensuring that the relevant <span> is rendered to hold an validation error message, should validation for the input element fail).

However, since we're now very firmly in the realm of generating our page elements client-side rather than from the server, with the use of KnockoutJS to control dynamically adding elements to the page, we can no longer rely on Html Helpers to write out the necessary elements with the required validation attributes.  Instead, we need to do all of this manually.

Manually adding data validation attributes

So, here's an example of the markup that we'll have to manually write in order to wire up the unobtrusive validation.  We'll examine this in more detail immediately afterwards:

<table>
	<thead>
		<tr>
			<th>Owner Writer Share</th>
			<th>Net Publisher Share</th>
		</tr>
	</thead>
	<tbody data-bind="foreach: MyViewModel.Rates">
		<tr>
			<td>
				<input type="number" min="0" max="100" data-input-type="percentage"
					   data-bind="value: $data.OwnerWriterShare,
							attr: { id: 'MyViewModel_Rates_' + $index() + '__OwnerWriterShare',
							name: 'MyViewModel.Rates[' + $index() + '].OwnerWriterShare' }"
					   data-val="true"
					   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
					   data-val-mustaddupto-amount="100"
					   data-val-number="The field Owner Writer Share must be a number."
					   data-val-required="The Owner Writer Share field is required."
					   value="">
			</td>
			<td>
				<input type="number" min="0" max="100" data-input-type="percentage"
					   data-bind="value: $data.NetPublisherShare,
							attr: { id: 'MyViewModel_Rates_' + $index() + '__NetPublisherShare',
							name: 'MyViewModel.Rates[' + $index() + '].NetPublisherShare',
							'data-val-mustaddupto-otherpropertyname': 'MyViewModel_Rates_' + $index() + '__OwnerWriterShare' }"
					   data-val="true"
					   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
					   data-val-mustaddupto-amount="100"
					   data-val-number="The field Net Publisher Share must be a number."
					   data-val-required="The Net Publisher Share field is required."
					   value="">
			</td>
		</tr>
	</tbody>
</table>

This markup represents the table that will have rows dynamically added to it at run-time by Knockout and which the two text boxes for our percentages that must both add up to 100.  We can see that many of the data-val-* attributes are simply written out in a hard-coded format (i.e. the data-val, data-val-mustaddupto, data-val-required etc. are all "static" values) and they won't vary from one row of dynamically added elements to the next.  This is all fairly simple so far, however, the Knockout specific data-bind attribute is quite special.

As well as containing the binding to the element's value, we also use the attr binding, which allows Knockout to render attributes on the element.  This is necessary for certain attributes, such as the data-val-mustaddupto-otherpropertyname attribute as this attribute needs to have a value which contains the exact id of the element that we need to examine as part of our validation.  Of course, since we're dealing with potentially many text boxes over many possible rows, these id values need to be dynamically generated and then referenced from the respective data-val-mustaddupto-otherpropertyname attribute.  This is achieved by having Knockout render those attributes for us, as well as rendering our id and name attributes on the element that requires validation.  If we examine the data-bind attributes for each of the <input> elements in the two <td>'s we can see that they both use a Knockout attr binding.  Each of the attr bindings renders both the id and the name of the input element:

attr: { id: 'MyViewModel_Rates_' + $index() + '__OwnerWriterShare', name: 'MyViewModel.Rates[' + $index() + '].OwnerWriterShare' }"

We can see that this binding also uses a special Knockout context property, $index,  which provides the attr binding with the numeric array index of the current data item being processed within the foreach loop.  The resulting markup that's rendered to the page is something similar to this:

<tr>
	<td>
		<input type="number" min="0" max="100" data-input-type="percentage"
			   id="MyViewModel_Rates_0__OwnerWriterShare"
			   name="MyViewModel.Rates[0].OwnerWriterShare"
			   data-val="true"
			   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
			   data-val-mustaddupto-amount="100"
			   data-val-number="The field Owner Writer Share must be a number."
			   data-val-required="The Owner Writer Share field is required."
			   value="50">
	</td>
	<td>
		<input type="number" min="0" max="100" data-input-type="percentage"
			   id="MyViewModel_Rates_0__NetPublisherShare"
			   name="MyViewModel.Rates[0].NetPublisherShare"
			   data-val-mustaddupto-otherpropertyname="MyViewModel_Rates_0__OwnerWriterShare"
			   data-val="true"
			   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
			   data-val-mustaddupto-amount="100"
			   data-val-number="The field Net Publisher Share must be a number."
			   data-val-required="The Net Publisher Share field is required."
			   value="50">
	</td>
</tr>
<tr>
	<td>
		<input type="number" min="0" max="100" data-input-type="percentage"
			   id="MyViewModel_Rates_1__OwnerWriterShare"
			   name="MyViewModel.Rates[1].OwnerWriterShare"
			   data-val="true"
			   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
			   data-val-mustaddupto-amount="100"
			   data-val-number="The field Owner Writer Share must be a number."
			   data-val-required="The Owner Writer Share field is required."
			   value="60">
	</td>
	<td>
		<input type="number" min="0" max="100" data-input-type="percentage"
			   id="MyViewModel_Rates_1__NetPublisherShare"
			   name="MyViewModel.Rates[1].NetPublisherShare"
			   data-val-mustaddupto-otherpropertyname="MyViewModel_Rates_1__OwnerWriterShare"
			   data-val="true"
			   data-val-mustaddupto="Owner Writer Share and Net Publisher Share Percentages must add up to 100."
			   data-val-mustaddupto-amount="100"
			   data-val-number="The field Net Publisher Share must be a number."
			   data-val-required="The Net Publisher Share field is required."
			   value="40">
	</td>
</tr>

Note how the id and name attributes contain the incrementing numeric index, giving each input element a unique id and name.  Furthermore, due to this, the second <td> of each row contains the additional data-val-mustaddupto-otherpropertyname attribute which correctly references that specific row's input element, allowing validation to be wired up to each dynamically added element in each dynamically added table row.

Ensuring validation is performed for dynamically added elements

Once we have Knockout rendering our id, name and validation specific element attributes, we're up and running with our complex validation.  Almost.  There's one final thing that needs to happen in order for the validation to work.  The jQuery Unobtrusive Validation library will initialize it's own internal cache of page elements that require validation when the page has first fully loaded.  Due to this, any page elements that are subsequently added to the page DOM by client-side script (such as our additional table rows, added by KnockoutJS) will not be included in the internal list of page elements that the Unobtrusive Validation will validate.  Therefore, we need a way of telling jQuery Unobtrusive Validation to re-build it's internal list of page elements each time we dynamically add or remove to or from the page any elements containing validation attributes.  This can be done quite simply with a short JavaScript function as follows:

function updateValidation() {
	$("#myForm").removeData("validator");
	$("#myForm").removeData("unobtrusiveValidation");
	$.validator.unobtrusive.parse("#createContract");
}

The #myForm selector represents an id of either a form, or some containing element that encompasses all of the dynamic parts of your web page.  It's important that this function is called by your own JavaScript code whenever a page element is added or removed from the page DOM.  This is usually easy enough to do as adding a table row is usually done in response to the user clicking some kind of "Add" button, which you'll usually have wired up via a Knockout click: binding to run a JavaScript function, usually defined as part of your Knockout view model.  For example, an additional <td> on our table could contain mark up similar to the following:

<td>
	<a href="#" title="Add" data-bind="click: addRateRow">
		<span>Add New Rate</span>
	</a>
</td>

And the addRateRow function would be called on the anchor tag's click event, adding a new row to the underlying Knockout view model - causing Knockout to re-render the table with the additional row and associated elements - and finally calling our simple updateValidation() function to ensure both jQuery Validation and jQuery Unobtrusive Validation are aware of the newly added elements:

koViewModel.addRateRow = function () {
	this.Rates.push(new Rate());
	updateValidation();
};

And with that, our custom complex jQuery Validation / Unobtrusive Validation with KnockoutJS dynamically created page elements is complete!

OWIN-Hosted Web API in an MVC Project – Mixing Token-based auth with FormsAuth

One tricky little issue that I recently came across in a new codebase was having to extend an API written using ASP.NET Web API 2.2 which was entirely contained within an ASP.NET MVC project.  The Web API was configured to use OWIN, the abstraction layer which helps to remove dependencies upon the underlying IIS host, whilst the MVC project was configured to use System.Web and communicate with IIS directly.

The intention was to use Token-based Http Basic authentication with the Web API controllers and actions, whilst using ASP.NET Membership (Forms Authentication) with the MVC controllers and actions.  This is fairly easy to initially hook up, and all authentication within the Web API controllers was implemented via a customized AuthorizationFilterAttribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class TokenAuthorize : AuthorizationFilterAttribute
{
    bool _active = true;

    public TokenAuthorize() { }

    /// <summary>
    /// Overriden constructor to allow explicit disabling of this filter's behavior.
    /// Pass false to disable (same as no filter but declarative)
    /// </summary>
    /// <param name="active"></param>
    public TokenAuthorize(bool active)
    {
        _active = active;
    }

    /// <summary>
    /// Override to Web API filter method to handle Basic Auth check
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // Quit out here if the filter has been invoked with active being set to false.
        if (!_active) return;

        var authHeader = actionContext.Request.Headers.Authorization;
        if (authHeader == null || !IsTokenValid(authHeader.Parameter))
        {
            // No authorization header has been supplied, therefore we are definitely not authorized
            // so return a 401 unauthorized result.
            actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, Constants.APIToken.MissingOrInvalidTokenErrorMessage);
        }
    }

    private bool IsTokenValid(string parameter)
    {
        // Perform basic token checking against a value
        // stored in a database table.
        return true;
    }
}

This is hooked up onto a Web API controller quite easily with an attribute, applied at either the class or action method level:

[RoutePrefix("api/content")]
[TokenAuthorize]
public class ContentController : ApiController
{
    [Route("v1/{contentId}")]
    public IHttpActionResult GetContent_v1(int contentId)
    {
        var content = GetIContentFromContentId(contentId);
        return Ok(content);
    }
}

Now, the problem with this becomes apparent when a client hits an API endpoint without the relevant authentication header in their HTTP request.  Debugging through the code above shows the OnAuthorization method being correctly called and the Response being correctly set to a HTTP Status Code of 401 (Unauthorized), however, watching the request and response via a web debugging tool such as Fiddler shows that we’re actually getting back a 302 response, which is the HTTP Status code for a redirect.  The client will then follow this redirect with another request/response cycle, this time getting back a 200 (OK) status with a payload of our MVC Login page HTML.  What’s going on?

Well, despite correctly setting our response as a 401 Unauthorized, because we’re running the Web API Controllers from within an MVC project which has Forms Authentication enabled, our response is being captured higher up the pipeline by ASP.NET wherein Forms Authentication is applied.  What Forms Authentication does is to trap any 401 Unauthorized response and to change it into a 302 redirect to send the user/client back to the login page.  This works well for MVC Web Pages where attempts by an unauthenticated user to directly navigate to a URL that requires authentication will redirect the browser to a login page, allowing the user to login before being redirected back to the original requested resource.  Unfortunately, this doesn’t work so well for a Web API endpoint where we actually want the correct 401 Unauthorized response to be sent back to the client without any redirection.

Phil Haack wrote a blog post about this very issue, and the Update section at the top of that post shows that the ASP.NET team implemented a fix to prevent this exact issue.  It’s the SuppressFormsAuthenticationRedirect property on the HttpResponse object!

So, all is good, yes?   We simply set this property to True before returning our 401 Unauthorized response and we’re good, yes?

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class TokenAuthorize : AuthorizationFilterAttribute
{
    // snip...
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var authHeader = actionContext.Request.Headers.Authorization;
        if (authHeader == null || !IsTokenValid(authHeader.Parameter))
        {
            HttpResponse.SuppressFormsAuthenticationRedirect = true;
            actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, Constants.APIToken.MissingOrInvalidTokenErrorMessage);
        }
    }
}

Well, no.

You see, the SuppressFormsAuthenticationRedirect property hangs off the HttpResponse object.  The HttpResponse object is part of that System.Web assembly and it’s intimately tied into the underlying ASP.NET / IIS pipeline.  Our Web API controllers are all “hosted” on top of OWIN.  This, very specifically, divorces all of our code from the underlying server that hosts the Web API.  That actionContext.Response above isn't a HttpResponse object, it's a HttpResponseMessage object.  The HttpResponseMessage object is used by OWIN as it’s divorced from the underlying HttpContext (which is inherently tied into the underlying hosting platform – IIS) and as such, doesn’t contain, nor does it have access to a HttpResponse object, or the required SuppressFormsAuthenticationRedirect property that we desperately need!

There are a number of attempted “workarounds” that you could try in order to get access to the HttpContext object from within your OWIN-compliant Web API controller code, such as this one from Hongmei at Microsoft:

HttpContext context;
Request.Properties.TryGetValue<HttpContext>("MS_HttpContext", out context);

Apart from this not working for me, this seems quite nasty and “hacky” at best, relying upon a hard-coded string that references a request “property” that just might contain the good old HttpContext.  There’s also other very interesting and useful information contained within a Stack Overflow post that gets closer to the problem, although the suggestions to configure the IAppBuilder to use Cookie Authentication and then to perform your own login in the OnApplyRedirect event will only work in specific situations, namely when you’re using the newer ASP.NET Identity, which itself, like OWIN, was designed to be disconnected from the underlying System.Web / IIS host.  Unfortunately, in my case, the MVC pages were still using the older ASP.NET Membership system, rather than the newer ASP.NET Identity.

So, how do we get around this?

Well, the answer lies within the setup and configuration of OWIN itself.  OWIN allows you to configure and plug-in specific “middleware” within the OWIN pipeline.  This allows all requests and responses within the OWIN pipeline to be inspected and modified by the middleware components.  It was this middleware that was being configured within the Stack Overflow suggestion of using the app.UseCookieAuthentication.  In our case, however, we simply want to inject some arbitrary code into the OWIN pipeline to be executed on every OWIN request/response cycle.

Since all of our code to setup OWIN for the Web API is running within an MVC project, we do have access to the System.Web assembly’s objects.  Therefore, the fix becomes the simple case of ensuring that our OWIN configuration contains a call to a piece of middleware that wraps a Func<T> that merely sets the required SuppressFormsAuthenticationRedirect property to true for every OWIN request/response:

// Configure WebAPI / OWIN to suppress the Forms Authentication redirect when we send a 401 Unauthorized response
// back from a web API.  As we're hosting out Web API inside an MVC project with Forms Auth enabled, without this,
// the 401 Response would be captured by the Forms Auth processing and changed into a 302 redirect with a payload
// for the Login Page.  This code implements some OWIN middleware that explicitly prevents that from happening.
app.Use((context, next) =>
{
    HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
    return next.Invoke();
});

And that’s it!

Because this code is executed from the Startup class that is bootstrapped when the application starts, we can reference the HttpContext object and ensure that OWIN calls execute our middleware, which is now running in the context of the wider application and thus has access to the HttpContext object of the MVC project’s hosting environment, which now allows us to set the all-important SuppressFormsAuthenticationRedirect property!

Here’s the complete Startup.cs class for reference:

[assembly: OwinStartup("Startup", typeof(Startup))]
namespace SampleProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureWebAPI(app);
        }
        
        private void ConfigureWebAPI(IAppBuilder app)
        {
            var config = new HttpConfiguration();

            // Snip of other configuration.

            
            // Configure WebAPI / OWIN to suppress the Forms Authnentication redirect when we send a 401 Unauthorized response
            // back from a web API.  As we're hosting out Web API inside an MVC project with Forms Auth enabled, without this,
            // the 401 Response would be captured by the Forms Auth processing and changed into a 302 redirect with a payload
            // for the Login Page.  This code implements some OWIN middleware that explcitly prevents that from happening.
            app.Use((context, next) =>
            {
                HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
                return next.Invoke();
            });

            app.UseWebApi(config);
        }
    }
}

Razor’s Conditional Attributes Bit Me!

When ASP.NET MVC 4 was released, Microsoft upgraded the Razor view engine that ships with ASP.NET MVC to version 2 and with it came a number of improvements. One of these improvements was a feature called “conditional attributes”.

 

Conditional Attributes are a new feature that allows you to shortcut “boilerplate” null check code when rendering an attribute to a HTML element. If you have a model property or a local variable that is used to output the “value” of a HTML element’s attribute that evaluates to NULL, the Razor engine will now automatically discard rendering the entire (empty) attribute.

 

Thus, whereas we’d previously have to do something like this:

<div @{ if(@Model.ClassName != null) { <text>class="@Model.ClassName"</text> } }>Content</div>

to ensure that, if @Model.ClassName was null, we wouldn’t render the entire class attribute, the new Conditional Attributes feature allows us to do this:

<div class="@Model.ClassName">Content</div>

and the Razor parser is smart enough to not render the class=”” literal attribute text if @Model.ClassName evaluates to null.  So we don’t get this:

<div class="">Content</div>

But instead we get much cleaner markup like this:

<div>Content</div>

 

Razor’s conditional attributes also work similarly with boolean values, so you can for example, cleverly output checked attributes on an input element defined as a checkbox like so:

<input type="checkbox" checked="@IsChecked">

If @IsChecked evaluates to true, the checked attribute is rendered with a value which is the same name as the attribute:

<input type="checkbox" checked="checked">

However, if @IsChecked evaluates to false, the entire attribute is not rendered.  Andrew Nurse, a developer on Microsoft’s Razor team, has a great blog post about this and the other new features in Razor v2.

 

So, this is all well and good, however, there is a huge gotcha that you need to be aware of surrounding conditional attributes!  I discovered this when upgrading a project originally built in ASP.NET MVC 3 (which had Razor v1 and thus didn’t have the conditional  attributes feature) to ASP.NET MVC 4.  This previously working project suddenly developed bugs that weren’t there before.  Upon inspection, it was due to Razor’s new conditional attributes feature that introduced a breaking change in my code.

 

Basically, I had a ASP.NET MVC strongly-typed View that displayed a grid of data.  As part of the model for this view was an object used to hold some basic data relating to how the user had configured the grid.  This was simply non-sensitive data such as the number of records per page, the column name upon which the grid was sorted and the sort order (ascending or descending).  This was output to the View as a number of hidden input fields within the view’s form, such that they could be posted back to the server upon each page request:

<input type="hidden" name="pagesize" value="@Model.PagingInfo.ItemsPerPage" />
<input type="hidden" name="sortname" value="@Model.PagingInfo.SortName" />
<input type="hidden" name="sortasc" value="@Model.PagingInfo.SortAscending" />

The problem was within that last line.  The @Model.PagingInfo.SortAscending is a boolean that evaluates to true if the user wants to sort ascending, or false if the user wants to sort descending.  In ASP.NET MVC 3, this would work just fine with the resulting output looking something like:

<input type="hidden" name="sortasc" value="false" />

when the user had elected to sort descending.  However, upon upgrading the project to ASP.NET MVC 4, Razor v2’s conditional attributes feature saw that the @Model.PagingInfo.SortAscending model property was a boolean and that it evaluated to false, and decided not to render the value attribute at all, thus my output became:

<input type="hidden" name="sortasc" />

When the user had selected to sort in an ascending manner, and the value of the @Model.PagingInfo.SortAscending property evaluated to true, the output was even more strange:

<input type="hidden" name="sortasc" value="value" />

This was the “cleverness” of the Razor parser kicking in and outputting the attribute’s name as it’s value when my boolean property evaluated to true.  This makes lots of sense when we’re outputting a series of checkboxes and we want one of them to be checked, which requires the checked=”checked” attribute to be added to the checked element, but not so much sense when we actually want to output the string “true” or “false” as a value attribute’s value in a hidden text input form field!

 

So whilst the output each time was valid HTML markup with no errors being displayed, this clearly affected the functionality of my page.  POSTs of this page, which would cause the page to redisplay (for example, when the user selected a different sort column or a different sort order) would always result in the grid sorting in a descending manner, irrespective of the user’s choice.

 

This was due to the Razor model binder finding no suitable value with which to bind the sortasc parameter of the controller method that was invoked when the page was posted back to the server:

public ViewResult List(string searchterm, string sortname, bool sortasc = false, int id = Page, int pagesize = PageSize)

Of course, the sortasc parameter’s default value was then always used, resulting in the “grid is always descending” behaviour!

 

This was an interested bug to hunt down within my code, and was also a particularly annoying one too, as the code had worked perfectly in ASP.NET MVC 3.  However, once it was discovered how and why this bug reared it’s head, it was also simple enough to fix.

 

The fix for this is to simply append .ToString() to all boolean variables/model properties that are used purely to render a true or a false attribute’s value on a HTML element.

 

Thus, my above code was fixed quite simply like so:

<input type="hidden" name="pagesize" value="@Model.PagingInfo.ItemsPerPage" />
<input type="hidden" name="sortname" value="@Model.PagingInfo.SortName" />
<input type="hidden" name="sortasc" value="@Model.PagingInfo.SortAscending.ToString()" />

The addition of the .ToString() forces the evaluation of the boolean and it’s resulting conversion to a string prior to the Razor engine’s parser being able to work it’s “conditional attribute” cleverness.  It simply results in the boolean’s string value being output as the attributes value every time, like this:

<input type="hidden" name="sortasc" value="True" />

So, whilst this issue didn’t manifest itself for me until I upgraded an older ASP.NET MVC 3 project to ASP.NET MVC 4, it’s quite feasible that a developer could write code like this from scratch in MVC 4 and expect the Razor parser to simply output the value of the boolean as the attribute value.  There’s an open case for this in the ASP.NET Web Stack issue tracker on CodePlex and whilst there is a simple enough workaround for the problem, it’s the “breaking change” nature of the issue that is most concerning.

 

Let’s be careful out there and remember to .ToString() our booleans!