InternetException

About coding and whatnot.

Handling Ajax errors in ASP.NET

clock December 22, 2012 09:58 by author n.podbielski

Yesterday I wrote about issue with Ajax postbacks in application I am working currently. Problem was with buttons that was triggering UpdatePanels to update asynchronously. After adding loading indicator I wanted to add error handling at client side.

As loading was handled by PageRequestManager events I was trying to achieve errors the same way. At first I created some html to show when error happens:

<div id="errorDialog" class="hidden">
    <div class="ui-widget center height100per width100per">
        <div class="ui-state-error ui-corner-all" style="padding: 0 .7em;">
            <p>
                <span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>
                <strong>Error:</strong>
                <br />
                <span id="errorDesc"></span></p>
        </div>
    </div>
</div>

It creates Alert container from jQueryUI theme as you can see here http://jqueryui.com/themeroller/. For me it's looks like this:

 

Styles are mostly from this library. Mine classes have meaningful names and are defined:

.width100per
{
    width:100%;
}
.height100per
{
    height:100%;
}


Folks at Microsoft does not added special event for handling errors in PageRequestManager, but args argument of event endRequesthandler can tell as if something bad happened inside our application:

pageManager.add_endRequest(function (sender, args) {
        if (args.get_error() != undefined) {
                alert("Ouch!");
alert(args.get_error().message);
  } });


Now we have to just add some logic to show error message inside our error container:

pageManager.add_endRequest(function (sender, args) {
        if (args.get_error() != undefined) {
            var errorMessage = args.get_error().message;
            args.set_errorHandled(true);
            jQuery('#errorDesc').html(htmlEncode(errorMessage).replace(":", "<br />"));
            jQuery('#errorDialog').dialog({
                width: 600,
                height: 300
            });
        }
        function htmlEncode(value) {
            return jQuery('<div/>').text(value).html();
        }
    });



htmlEncode function replaces special HTML charachters like < or > with HTML entities. It's works by creating in-memory-only div element, and then setting some HTML as text and getting this as HTML. Simple as that. I added replacing : with HTML next line to show error description from C# in below summary of exception. After that dialog is opening to show to user that something bad happens.

Dialog is much bigger then it needs to be but I think that user must know that it's something serious and bigger message helps with that Smile

That's all!



Global UpdatePanel loading indicator in ASP.NET

clock December 21, 2012 10:48 by author n.podbielski

When I started working on application I am working right now, one of first things I noticed, that was not entirely wrong but was inconvenient: when user clicked on some button that triggers update panel you was not entirely sure it worked or not. Why? Because of three things:

1. I don't know who was developing application before me but sufice to say this person was not thorough with work :) So in many places code worked like Ash in Pokemon (Catch'em all!) with big try catch in whole methods. When exception happend it was not propagated to browser. Maybe it worked, or failed or is still working, you would never known.

2. Code was not optimized. It was slow actually. When it should just add simple entity to DB it was running several seconds. User was not aware of that.

3. Use of UpdatePanels with asynchronous postback and without loading indicator.

 

Changing code to get rid of all 'pokemon error catching' it was work for several days. Not solution I was looking for. It had to be done but not in that moment. Same thing with code optimization.

So I had to add some loading gif. But how to add it to all UpdatePanels? In ASP.NET there is UpdateProgress control but it is associated with single UpdatePanel and useless in that case.

What about ASP.NET Ajax API? PageRequestManager have several events for handling such things.

 

In that particular case it have one usefull event: add_endRequest.

 

Enough with rumbling! Let's jump to the code! :)

 

First we have to create some html code to show  when loading is pending. I used this great site to obtain simple .gif image to show: http://www.ajaxload.info/

With generated image i created HTML like this:

<div id="loadDialog" class="hidden">
    <div class="center height100per width100per">
        <img class="loadingImg height100per" src="<%=Page.ResolveUrl("~/image/loadingCircle.gif") %>"
            alt="Loading" />
    </div>
</div>



And some CSS to style this:

/*miscelanous*/
.hidden
{
    display:none;
}
.center
{
    text-align:center;
    margin:auto;
}
.width100per
{
    width:100%;
}
.height100per
{
    height:100%;
}
/*load dialog*/
div.loadDialog img.loadingImg
{
    height: 100%;
}


Wait, it's not there yet. This is just html, initially hidden. To show this I used jQueryUI modal dialog. This will prevent users clicking here and there. They might broke something, you know. Here is JS snippet I used:

    var dialogSelector = '#loadDialog';
    jQuery(function () {
        jQuery(dialogSelector)
                    .removeClass("hidden")
                    .dialog(
                        {
                            modal: true,
                            draggable: false,
                            closeOnEscape: false,
                            resizable: false,
                            width: 10,
                            height: 100
                        }).parent().css(
                        {
                            position: 'fixed'
                        });
        jQuery(dialogSelector).parent().find('.ui-dialog-titlebar').hide();
        jQuery(dialogSelector).dialog('close');
    });

    var pageManager = Sys.WebForms.PageRequestManager.getInstance();
    pageManager.add_beginRequest(function () {
        loadTimeOut = setTimeout(function () {
            jQuery(dialogSelector).dialog();
        }, 2000);
    });
    pageManager.add_endRequest(function () {
        if (loadTimeOut) {
            clearTimeout(loadTimeOut);
        }
        jQuery(dialogSelector).dialog('close');
    });


This function will run on load, show our loading dialog and instantly hide it again. This way it will show dialog without second initialization when it's gonna be really needed. First initialization is somewhat complicated so I decided to do it once. To show dialog after that I just call:

jQuery(dialogSelector).dialog();



Now let's explain what is happening in initialization. jQueryUI have solution for hiding html elements, so first thing I do is to remove my 'hidden' class. Then I create dialog with modal option, disabled dragging and resizing, closing on [ESC] key press. This will disable any user interaction with dialog itself and whole page.
Great. Width and height options are to make it as small possible (it will scale to image size anyway). After that setting position as fixed will assure that our dialog is always on center of the page. jQueryUI creates some nifty title bar for dialogs we don't want, so line:

jQuery(dialogSelector).parent().find('.ui-dialog-titlebar').hide();



will make it go away.
After that dialog is closed.
I decided that is also good thing to not flash with this dialog user every time something, even smallest thing is updating. User attention span is about 2 seconds. After that they start wondering and clicking again. So 2 seconds is good time to show dialog. For that is timeout:

    var pageManager = Sys.WebForms.PageRequestManager.getInstance();
    pageManager.add_beginRequest(function () {
        loadTimeOut = setTimeout(function () {
            jQuery(dialogSelector).dialog();
        }, 2000);
    });

 And to handle end request event:

 

    pageManager.add_endRequest(function () {
        if (loadTimeOut) {
            clearTimeout(loadTimeOut);
        }
        jQuery(dialogSelector).dialog('close');
    });


which will clear timeout of request with completion time < 2s and then closes dialog it time was more then 2 seconds. That's all. In my case it give nice looking dialog like this: