Ioannis Panagopoulos blog

Tutorials on HTML5, Javascript, WinRT and .NET

Handling errors and internet connectivity problems in Windows 8 Apps with navigation (WinJS)

by Ioannis Panagopoulos

In this post we will explore a generic way of handling unpredicatble errors/lost connectivity in our Windows 8 Apps developed with HTML5 and Javascript. The two requirements we need to tackle are as follows:

  • There is a chance that while our application is running, internet connectivity will be lost. We need to know when this happens in order to inform the user and possibly handle the problem while preserving application state.
  • Unpredicatble errors may occur that will cause a general exception. We need to "catch" those errors, informing the user with a generic (and apologetic) error message and maybe transmit some useful details about the error to a service we have implemented for this purpose.

Handling internet connectivity problems

First we need a way to verify whether the app has connectivity to the internet. This can be done by using the following function:

utilities.isConnected=function() {
	var connectivity=Windows.Networking.Connectivity;
	var profile = connectivity.NetworkInformation.getInternetConnectionProfile();
	if (profile) {
		return (profile.getNetworkConnectivityLevel() != connectivity.NetworkConnectivityLevel.internetAccess);
	}
	else {
		return false;
	}
}					

The function returns true if the application is connected to the internet and false if it is not. This function can be used in a page whenever the user clicks on a button or in general an action will be invoked that will trigger a WinJS.xhr or something similar and if it returns false the application should prevent the action from being executed.

The same can be applied when the user navigates to a page that uses the internet in its "onload" event. But in this case what can you do? Meaning that the user reaches the page/pages that to fetch data "on load", the connection is down so nothing is fetched and then you need to display a button or something or start a timer that checks the coneectivity and at some time refreshes the page.

Or you could easily and with a few lines of code handle this case generally as follows: The idea is to use a "nointernet" page and lead the user there when you detect there is no internet. Then you prompt the user to hit the back button or a button you provide when he feels that the connection has been re- established. So let's see how this works:

First you need to implement a simple "no internet" page. A snapshot of the page is given below.

demo nointernet page

In the navigator.js file that handles the navigation, we find the _navigated function that is called whenever a user goes from one page to another before the load event of the new page and we add the following lines at the top:

_navigated: function (args) {
	if (args.detail.location.indexOf("nointernet") == -1 && !utilities.isConnected()) {
		nav.navigate("/pages/nointernet/nointernet.html");
		return;
	}	
	// ...rest of the function			

This means that if we are not already in the "nointernet" page and the internet connectivity has been lost instead of going wherevere the user chose to go we navigate to the "nointernet" page.

In the "nointernet" page the click event handler of the "Retry" button calls WinJS.Navigation.back();

And this is it. With just a few lines of code you can handle with dignity all connectivity issues that may occur during the user's navigation in all application pages

Handling unpredicatble erros

The second requirement states that the app should be able to handle unpredictable errors in a graceful manner. We will follow a similar approach with an "error" page dedicated just for that.

demo nointernet page

The "Retry" button with just call again WinJS.Navigation.back() hoping that ther error was temporar. But how do we send the user to this page upon an unpredictable error?

We just need to handle the onerror event in the default.js file (or in some other file) as follows:

app.onerror = function (customEventObject) {
    var errorMessage = '';
    var errorName = '';
    if (customEventObject.detail.error) {
        errorMessage = customEventObject.detail.error.message;
        errorName = customEventObject.detail.error.name;
    }
    else {
        errorMessage = customEventObject.detail.exception.message;
        errorName = 'Exception';
    }
    var optionsObject = { errName: errorName, errMsg: errorMessage };
    nav.navigate("/pages/error/error.html", optionsObject);
    return true;
}				

Now if you want to take this one step further and have some private service listening for those errors (so you know what your users are experiencing) you can implement a simple ASP.MVC 3 application (empty), add just one controller (say ServicesController) with a single Action called Error:

public class ServicesController : Controller
{
    public JsonResult Error(string errName,string errMsg)
    {
        // Store the data in the database or whatever 
        return Json(new {stored=true},JsonRequestBehavior.AllowGet);
    }

}				

You host this service in the net and then in the "error" page (on ready event) you write something similar to the following:

ready: function (element, options) {
    element.querySelector("#buttonRetry").onclick = function (ev) {
        WinJS.Navigation.back();
    }

    WinJS.xhr({ url: 'http://localhost:10162/Services/Error?errName=' + 
                options.errName + '&errMsg=' + options.errMsg }, function (data) {

    });
}				

Now you have a personal bug reporting tool so you know the problems that occur for each one of the deployed application instances out there.

blog comments powered by Disqus
hire me