Software Development12 May 2010 08:18 pm

For several years now we have been using a simple “pattern” to make error handling a little easier.  I call this IUserTargetedException pattern, after the interface that is its primary component.

The Problem

The problem that this pattern is intended to solve revolves around how to present useful (actionable) information to the end user when exceptions occur but at the same time hide technical, sensitive or otherwise inappropriate information.

Exceptional situations can be generalized into the following categories:

  1. A low level system error occurs about which the end user can’t really do anything to solve, except maybe try again later or call the help desk.
  2. A low level system error occurs about which the end user can take corrective action if properly informed.
  3. An exception case is detected by the application logic and a meaningful custom exception is thrown.

Some Examples

1. The Oracle Data Provider for .Net, in the event of a connection failure, has the ill manners to include all the details of the connection string (including account credentials if present) in the text of the exception. This is the kind of exception that one almost certainly does not want the end users to see. Setting aside the fact that it contain sensitive data that the user should not have access to, even if technically savvy enough to know what the error means, what can the user do?  Typically there is nothing that an end user can do to fix a connectivity problem between application components.

2. On the other hand, lets say the same data provider threw an exception that resulted from a unique key constraint violation. Again the message provides some technical details about the data schema that we probably want to keep hidden. However this time, the user, properly informed, can take action to correct the problem. He can rename the record he was trying to save to give it a unique name.

There is a third scenario. Prior to processing the record, the domain logic performs a permissions check and determines that the current user is not authorized to modify this record and throws an appropriate exception. In this case the business situation may require that the user be told in detail what permissions they are lacking so that they can request them from their administrator. So the code that throws the error needs to provide a user appropriate exception message.

So we have three scenarios where exceptions occur and in each case, the end user needs to be told something. In the first case, we probably want to keep it general: “An unexpected system error has occur. Please try again later.” In the second, we want to translate the original exception message into something actionable by the user. In the latter, the exception message is actionable as such.

The problem is how to distinguish between these at the UI level. Typically this is where we put our error handling. We can put it at a lower level, but if we do, we still need that final, top level error handler in the UI; the last defense against the unexpected. So if possible, its easiest if we can simply put all our error handling there, to keep our code dry.

The Solution

To solve this problem, we create an interface as follows:

public interface IUserTargetedException
{
    string UserTargetedMessage { get; }
}

Then in our top level error handler, we catch all exceptions and test each to see if they implement the IUserTargetedException interface.  For those that do, we display the UserTargetedMessage to the user.  For those that do not, we display some generic “Unexpected system error” type of message.  No mater what we show the user, we will likely log all the details for diagnostic purposes.

Application to the Problem Scenarios

Lets see how we would use this approach in each of our scenarios.

In the first scenario, we have an un-anticipated system exception.  In this case, the exception is not created by our code and thus will not be marked as a user targeted exception.  It will be reported using the generic message.

In the second scenario, we have an anticipated system exception.  This exception gets caught at a lower level, where it was expected.  In the above example, this would be in our Data Access Layer.  The DAL understands the business meaning of the exception and can provide a user actionable message, so it is appropriate to an error handler there.  This handler wraps the original exception in an one that implements IUserTargetedExcdeption and gives it a user actionable message.  Then the new exception is thrown, to be caught by the top level handler.

In the third scenario, we are throwing a custom application exception.  The code throwing the exception is generally expected to know the business meaning of the exception and is responsible for providing a user actionable message.  In this case, all we need to do is use a custom exception that implements IUserTargetedException.

Variations

There are several variations on this pattern.

  • One simply uses IUserTargetedException as a marker interface.  (An interface that has no members but simply marks a type in some way.)  In this case, the Exception.Message property is expected to contain a user appropriate message.
  • Alternately, in .Net and many other modern languages, marker interfaces have fallen into disfavor, with attributes being the prefered way to decorate a class.  So in this case a UserTargetedExceptionAttribute can be created.  This has the slight downside of being a little harder to test for in most languages.
  • A final option, available in the .Net framework is to use the Exception.Data dictionary and a system wide defined key constant to define an entry in the dictionary that will either contain a string, the user appropriate message, or a boolean indicating whether Exception.Message is user appropriate.The use of Exception.Data has the advantage in that, in scenario two, we don’t need to wrap the original exception, we can simply tag it and throw it again using throw without any arguments.  This allows the exception to bubble up with its original call stack in place.  That can simplify any logging tasks that must be performed.  On the other hand, wrapping the exception, or throwing a new one w/o wrapping can be safer in situations where you really need to make sure sensitive data does not reach the UI.

In the end, the goal is simply to provide some means of indicating if the exception contains a user appropriate message, with the default being that it does not.

Software Development02 Apr 2010 07:35 am

I was recently working on a web page where we were using jQuery slideUp and slideDown animations, in conjunction with hide and show to reconfigure the page on-the-fly based on user interaction. We encountered a problem however in that in some cases a single user actions would result in numerous divs and table rows needing to be hidden others shown. The normal asynchronous way that animation occurs in jQuery would cause the screen to dissolve into chaos for the duration of the animations, leaving the user utterly confused as to what just happened.

To solve this problem, we wanted our animations to run either synchronously or at least sequentially. A quick google search revealed that synchronous animations are not possible because JavaScript runs on the UI thread. Thus, any synchronous animation would hang the browser for the duration. On the other hand, as anyone with any jQuery animation experience knows, it is simple to chain animations to run sequentially, using the callback argument that is part of the signature every animation method.

Our problem was that we needed a way to do sequential animations on sets of elements. For example, a call like $(“.widgets”).slideDown() causes all widgets to slide down concurrently. We wanted them to slide down one after another, so that the user can better track with their eye what is happening.

Moreover, some additional logic in the handling of the same user event (say a button click) would cause all nuggets to slide up and the #fooBar element slide down as well. We wanted all this to happen sequentially without the disparate sets of logic that made these determinations needing to know of or explicitly coordinate with each other.

To solve this problem I wrote the following simple pair of JavaScript functions that work together to 1) register animations to run sequentially and then 2) kicks off the next animation in the queue once the previous one completes.

var animationFIFOQueue = new Array();
 
function doAnimationSequentially(action, domObj) {
    var animation = { action: action, domObj: domObj };
    var needToStartAnimationChain = animationFIFOQueue.length == 0;
    animationFIFOQueue.push(animation);
    if (needToStartAnimationChain) {
        doNextAnimation();
    } 
}
 
function doNextAnimation() {
    var nextAnimation = animationFIFOQueue.shift();
    if (nextAnimation) {
        if (nextAnimation.action == "slideDown") {
            $(nextAnimation.domObj).slideDown(doNextAnimation); 
        }
        if (nextAnimation.action == "slideUp") {
            $(nextAnimation.domObj).slideUp(doNextAnimation); 
        }
        if (nextAnimation.action == "hide") {
            $(nextAnimation.domObj).hide();
            doNextAnimation();
        }
        if (nextAnimation.action == "show") {
            $(nextAnimation.domObj).show();
            doNextAnimation();
        }
    }   
}

Note that the code also allows for the insertion of non-animated (and hence synchronous) hide and show commands into the animation sequence. We used this for hiding and showing table rows elements in coordination with sliding the content of the rows since rows themselves to not animate well.
Obviously the code can easily be expanded to handle other animation commands as well (such as fadeIn and fadeOut.)

.Net Development10 Mar 2010 09:50 pm

I have found that the DefaultModelBinder, when binding to arrays, has an irritating quirk; dare I say bug? If the array is already instantiate in the model, the model binder will attempt to call .Clear() and then .Add() on the array (because all arrays support the IList interface). However arrays are fixed size lists. (IList.IsFixedSize returns true.) As a result, calling .Clear() throws a NotSupportedException as shown in the following stack trace:

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
--System.NotSupportedException : Collection is read-only.
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, ref SignatureStruct sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at System.Web.Mvc.DefaultModelBinder.CollectionHelpers.ReplaceCollection(Type collectionType, Object collection, Object newContents)
at System.Web.Mvc.DefaultModelBinder.UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at ArrayModelBinderTests.DefaultModelBinder_should_sould_fail_to_bind_to_non_null_arrays_in_model() 
--NotSupportedException
at System.SZArrayHelper.Clear()
at System.Web.Mvc.DefaultModelBinder.CollectionHelpers.ReplaceCollectionImpl(ICollection`1 collection, IEnumerable newContents)

In my humble opinion, what the model binder should do in the case of arrays is to ignore any already instantiated model and instead always create a new one and return it. This is what it does when there is no pre-existing instance. (i.e the model is null).

Why is this important you may ask? I mean, in general when binding to a model, the binder is creating the model from scratch anyway so won’t the array always be null? Well not always. Consider the following model:

public class FamilyModel
{
    public string MyName { get; set; }
    public string MyWifesName { get; set; }
 
    private string[] _myChildrensNames;
    public string[] MyChildrensNames
    { 
        get 
        { 
            return _myChildrensNames 
                ?? (_myChildrensNames = new string[0]);
        }
        set { _myChildrensNames = value; }
    }
}

In this case, in order to avoid the need to check MyChildrensNames for null every time it is accessed, we ensure that it is never null. If I have no children, the property reasonably returns an empty collection. This is an example of the null object pattern.

Given such a model, we will encounter the described problem every time we attempt to bind to it.

To resolve this, I have written the following model binder which can be registered for any type of array. It uses something akin to a decorator pattern to wrap the default model binder. The decorator simply forces the model to null before invoking the default binder, effectively sidestepping the problem.

public class ArrayModelBinder : DefaultModelBinder
{
	public override object BindModel(
            ControllerContext controllerContext, 
            ModelBindingContext bindingContext)
	{
		var originalMetadata = bindingContext.ModelMetadata;
 
		bindingContext.ModelMetadata = new ModelMetadata(
			ModelMetadataProviders.Current,
			originalMetadata.ContainerType,
			() => null,  //Forces model to null
			originalMetadata.ModelType,
			originalMetadata.PropertyName
			);
 
		return base.BindModel(controllerContext, bindingContext);
	}
}

You can download the complete source and unit tests here.

« Previous PageNext Page »