ASP.NET APIController 500 Internal Server Errors


I had a situation where locally, calling an APIController method worked fine but when I uploaded the site to an Azure service, every time I called any method I would get back a 500 Internal Server Error.  The project had a mix of standard MVC Controllers and APIControllers and the MVC Controllers worked fine but the APIControllers crashed every time.  In an attempt to figure out what was going on, I logged into the remote server and checked the IIS logs but found nothing. I could see that 500 error being returned, but got nothing from the logs or the Event Viewer.

In a normal ASP.NET MVC project you could turn off custom errors through the web.config with something like this, but that did not provide any extra information.

<customErrors mode="Off" />

After some digging, I found out that in order to return more detailed error messages from an APIController, you have to set the following setting while the application starts.  I dropped this in the Global.asax.cs Application_Start method and it provided the detailed error messages I needed.


GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

IE9 Bug: Div height grows on hover when overflow is set to auto


It turns out that if you have a div set to overflow:auto, the contents of that div are wider than the containing div, and you have an element with a :hover css class inside that div that IE9 will start messing with the height of the div whenever the mouse is moved inside it. (see below)

Image

 

The work around for this is quite easy.  All you need to do is specify a height on the wrapper div and set the inner div to a height of 100%.  You can see an example of the problem and the solution here.

 

Posted in Uncategorized. Tags: , , . 1 Comment »

ASP.NET MVC: LessThan and GreaterThan Validation Attributes


ASP.NET MVC ships with a handy Compare attribute that allows you to compare two inputs and display a validation message if they do not match. This is great for sign up pages where a password needs to be entered twice and we need to ensure that they are equal but aside from that, I haven’t found any other use for the Compare attribute. What I have found that I have needed more are LessThan and GreaterThan attributes that allow you to compare two inputs and ensure that one is less than or greater than the other. The ASP.NET MVC Framework doesn’t not come loaded with such attributes so using the Compare attribute as a template, I have created them.

You can download a project here that has the complete source code and test pages for these attributes.

We will start first with the validation attribute:

public class NumericLessThanAttribute : ValidationAttribute, IClientValidatable
{
    private const string lessThanErrorMessage = "{0} must be less than {1}.";
    private const string lessThanOrEqualToErrorMessage = "{0} must be less than or equal to {1}.";                

    public string OtherProperty { get; private set; }

    private bool allowEquality;

    public bool AllowEquality
    {
        get { return this.allowEquality; }
        set
        {
            this.allowEquality = value;
                
            // Set the error message based on whether or not
            // equality is allowed
            this.ErrorMessage = (value ? lessThanOrEqualToErrorMessage : lessThanErrorMessage);
        }
    }        

    public NumericLessThanAttribute(string otherProperty)
        : base(lessThanErrorMessage)
    {
        if (otherProperty == null) { throw new ArgumentNullException("otherProperty"); }
        this.OtherProperty = otherProperty;            
    }        

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, this.OtherProperty);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherProperty);   
            
        if (otherPropertyInfo == null)
        {
            return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "Could not find a property named {0}.", OtherProperty));
        }

        object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);

        decimal decValue;
        decimal decOtherPropertyValue;

        // Check to ensure the validating property is numeric
        if (!decimal.TryParse(value.ToString(), out decValue))
        {
            return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "{0} is not a numeric value.", validationContext.DisplayName));
        }

        // Check to ensure the other property is numeric
        if (!decimal.TryParse(otherPropertyValue.ToString(), out decOtherPropertyValue))
        {
            return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "{0} is not a numeric value.", OtherProperty));
        }

        // Check for equality
        if (AllowEquality && decValue == decOtherPropertyValue)
        {
            return null;
        }
        // Check to see if the value is greater than the other property value
        else if (decValue > decOtherPropertyValue)
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }            

        return null;
    }

    public static string FormatPropertyForClientValidation(string property)
    {
        if (property == null)
        {
            throw new ArgumentException("Value cannot be null or empty.", "property");
        }
        return "*." + property;
    }       

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {           
        yield return new ModelClientValidationNumericLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality);
    }
}

Like the compare attribute, this attribute will compare against another value on the form. The other property name is passed into the attributes constructor. There is also another named parameter, AllowEquality, which allows you to specify whether or not the value being validated can be equal to the ‘other’ property. The IsValid method is pretty straightforward and compares the two values to see if they are valid.

The last method, GetClientValidationRules creates a ModelClientValidationNumericLessThanRule class defined below:

public class ModelClientValidationNumericLessThanRule : ModelClientValidationRule
{
    public ModelClientValidationNumericLessThanRule(string errorMessage, object other, bool allowEquality)
    {
        ErrorMessage = errorMessage;
        ValidationType = "numericlessthan";
        ValidationParameters["other"] = other;
        ValidationParameters["allowequality"] = allowEquality;
    }
}

This class specifies the client validation type and parameters that will be loaded into the data attributes of the input on the html page. Here we have specified that the jQuery client validation type has a name of ‘numericlessthan’ and that it will accept to parameters values named ‘other’ and ‘allowEquality’.

Now that we have created these two classes, we can now generate a model to test the validation:

public class NumericLessThanViewModel
{
    public decimal MaxValue { get; set; }

    [NumericLessThan("MaxValue", AllowEquality = true)]
    [Display(Name="Value")]
    public decimal Value { get; set; }
}

For this to work we need at least two properties on the model; one that specifies the maximum value and another that will be used for the user input. On the user input property, add the NumericLessThan attribute and specify the name of the ‘other’ property to which it will be compared and whether or not equality is allowed. The ‘other’ value will usually be loaded as a hidden field in the form.

At this point just the server side validation has been setup. We need to add a javascript file as well to enable client side validation.

jQuery.validator.addMethod('numericlessthan', function (value, element, params) {
    var otherValue = $(params.element).val();

    return isNaN(value) && isNaN(otherValue) || (params.allowequality === 'True' ? parseFloat(value) <= parseFloat(otherValue) : parseFloat(value) < parseFloat(otherValue));
}, '');

jQuery.validator.unobtrusive.adapters.add('numericlessthan', ['other', 'allowequality'], function (options) {
    var prefix = options.element.name.substr(0, options.element.name.lastIndexOf('.') + 1),
    other = options.params.other,
    fullOtherName = appendModelPrefix(other, prefix),
    element = $(options.form).find(':input[name=' + fullOtherName + ']')[0];

    options.rules['numericlessthan'] = { allowequality: options.params.allowequality, element: element };
    if (options.message) {
        options.messages['numericlessthan'] = options.message;
    }
});

function appendModelPrefix(value, prefix) {
    if (value.indexOf('*.') === 0) {
        value = value.replace('*.', prefix);
    }
    return value;
}

The first method in the code above adds the actual method that is called when validating the input. In it we check to see if both values are numbers and depending on whether or not we specified to allow equality, we check to ensure that the user input is less than or equal to the other value.

The second method adds the rule to the set of jQuery validation adapters and supplies the wiring up of the parameters that will be supplied to the validation method.

And that is it. The ASP.NET MVC framework and the jQuery validation libraries will take care of the rest.

In the downloadable project above I have included a NumericGreaterThan attribute as well but as you can image, the code is almost identical to the LessThan attribute so I will not be going over it here.

ASP.NET MVC: Displaying Client and Server Side Validation Using Error Icons


In a previous post I showed how you could display both client and server side validation using qTip tooltips. In this post I will show how you can display an error icon next to the field that is invalid and then when the user hovers over the icon, display the error message (demonstrated below).

As done previously I will be using the same example project from this post where we created a dialog form which was submitted via Ajax.

You can download the complete solution for this example here.

First, the error icon. I utilized the ui-icon-alert class that comes with jQuery UI to display the error icon. But, to get the icon to display correctly without having to create a containing div element around the icon, we need to add a new class to the jquery.ui.theme.css file. Open up the default jquery.ui.theme.css file or if you have added a custom theme, the jquery-ui-[version number].custom.css file and find the states and images sub section under the Icons section. Add the following css class to the list of classes there.

.ui-state-error-icon { display:inline-block;  width: 16px; height: 16px; background-image: url(images/ui-icons_cd0a0a_256x240.png);  }

This class will allow a 16 x 16px icon from the error images png to be displayed in an empty element.

Next we need to change the onError function in the jquery.validate.unobtrusive.js javascript file. Open that file and replace the onError function with that shown below.

function onError(error, inputElement) {  // 'this' is the form element        
    var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
    replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
            
        // Do not display the error message
        //container.empty();
        //error.removeClass("input-validation-error").appendTo(container);

        // If the error message is an empty string, remove the classes
        // from the container that displays the error icon.  Otherwise
        // Add the classes necessary to display the error icon and
        // wire up the qTip tooltip for the container
        if ($(error).text() == "") {
            container.removeClass("ui-state-error-icon").removeClass("ui-icon-alert");
        }
        else {
            container.addClass("ui-state-error-icon").addClass("ui-icon-alert");

            $(container).qtip({
                overwrite: true,
                content: $(error).text(),
                style: {
                    classes: 'ui-tooltip-red'
                }
            });
        }
    }
    else {
        error.hide();
    }
}

Here instead of displaying the error message in associated container, we are displaying the alert icon and wiring up a qTip tooltip to display the error text. (Make sure in your Layout or MasterPage that you reference the jquery.validate.unobtrusive.js javascript file not the jquery.validate.unobtrusive.min.js file.)

If you run the application now all client side errors will be displayed using little error icons as pictured above and if the user hovers over the icon, the error message will be displayed in the tooltip.

To make server side validation messages appear in the same way we need to add another javascript function to each page. Create a new javascript file named jquer.qtip.validation.js and paste the following code into it.

$(function () {
    // Run this function for all validation error messages
    $('.field-validation-error').each(function () {

        // Get the error text to be displayed
        var errorText = $(this).text();

        // Remove the text from the error message span
        // element and add the classes to display the icon
        $(this).empty();
        $(this).addClass("ui-state-error-icon").addClass("ui-icon-alert");

        // Wire up the tooltip to display the error message
        $(this).qtip({
            overwrite: true,
            content: errorText,
            style: {
                classes: 'ui-tooltip-red'
            }
        });     
    });
});    

Here we are doing the same thing we did for client side validation except we are iterating over all elements with the field-validation-error class and removing its text, displaying the icon, and placing the error message in the tooltip. Make sure that on every form where you have server side validation displayed that you reference the jquery.qtip.validation.js javascript file.

There you have it. Client and server side validation displayed using error icons and tooltips.

ASP.NET MVC: Internal Server Error (500) on Action Method Returning Json Result


The ASP.NET MVC framework allows you to easily return Json from an action method. This makes jQuery Ajax calls very easy to implement, as shown below.

The JavaScript

$(.button).getJSON('/Home/GetJsonData', 
                   { id = 34 },
                   function(data) {
                      // Do something with it
                   }
);

The Action Method

public ActionResult GetJsonData(int id)
{
     Person person = this.personService.GetPerson(id);     
     return Json(person);
}

There is only one problem with the above action method. If you attempt to run it, the call to the ActionMethod will result in a Internal Server Error (Error 500). The reason is that by default data can only be retrieved using a POST operation if your action method returns a Json result. To make this work with a GET request, all you need to use is the overloaded Json() method shown below.

public ActionResult GetJsonData(int id)
{
     Person person = this.personService.GetPerson(id);     
     return Json(person, JsonRequestBehavior.AllowGet);
}