Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

C# and .NET Tips and Tricks

Quests in programming in .NET

Μάιος 2013 - Δημοσιεύσεις

A simple way to detect memory leaks in C# and how to create one with events :)

In this post we will see a simple code fragment that can be used to detect memory leaks (more specific objects that are not cleaned by the garbage collector) and we will do it in the context of an interesting memory leak that can be created when using event delegates.

The memory leak with event delegates

Suppose you have an application in WPF with a single window that presents some money values in a specific currency (say EURO). At a specific instance you may have more than one such windows open.

Now a requirement comes that defines that you need to be able to change the currency (say from euro to dollar) and have this change be reflected immediately to any currently open window displaying the money value. One easy way to tackle this is shown in the following figure:

The "settings" object is static with a static property "Currency" with the current currency and an event called "OnCurrencyChanged" that is fired when the currency is changed. The "Window" class ("window1" nad "window2" objects) defines a method "currencyChanged". When a window is opened it attaches the "currencyChanged" method to the "OnCurrencyChanged" event. This method will be called whenever the event is fired and will be responsible for converting the money values in the windows. Let's see some code for that. First the "settings" class:

public static class settings
{
    public static event Action OnCurrencyChanged;

    public static void ChangeCurrency(string newCurrency)
    {
        //...
        if (OnCurrencyChanged != null)
            OnCurrencyChanged(newCurrency);
    }

}				

The code for the window with the money values has the "currencyChanged" method:

public partial class MoneyWindow : Window
{
    public MoneyWindow()
    {
        InitializeComponent();
    }

    public void currencyChanged(string newCurrency)
    {
        // Change the view to reflect the change here
    }
}				

The initializer of the window with the money values will be as follows:

MoneyWindow dlg = new MoneyWindow();
dlg.Show();
settings.OnCurrencyChanged += dlg.currencyChanged;	

Which in other words defines that when the window is created it will be listening to the "OnCurrencyChanged" event.

And you have your memory leak right there! Even if you close the window in some time, the event you have attached still keeps it "connected" to your application and therefore it will never be garbage collected. Just for a reminder, the objects are destroyed by the garbage collector when there are no other objects pointing to them. But in this case you have an "implicit" connection with the event. If you execute the demo application (here) you will see that opening and closing the window keeps consuming more and more memory which never gets freed (it helps to have the "Task Manager" open to test that). The solution is simple and it just requires you to unsubscribe from the event with "-=" when the window is closed. But say you are in a large application you are not sure whether an object gets garbage collected or not and wanna check that then what can you do?.

Detecting memory leaks

Or better checking whether an object will get garbage collected. Implement in your project a class like the following:

public static class MemoryLeak
{
    public static WeakReference Reference { get; private set; }

    public static void CheckObject(object ObjToCheck)
    {
        MemoryLeak.Reference = new WeakReference(ObjToCheck);
    }

    public static void IsItDead()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (MemoryLeak.Reference.IsAlive)
            Debug.WriteLine("Still here");
        else
            Debug.WriteLine("I 'm dead");
    }
}				

The code creates a weak reference to an object. The "weak reference" means that while it keeps a reference to the object this does not prevent the garbage collector from cleaning it (in other words this reference does not count in terms of collecting the object when not referenced). So we create the reference and then by calling "IsItDead" we just force the GC to collect any unneeded objects. If the object in question still persists then we have a memory leak.

For our example above, when we create the window we create a weak reference to the window object. Then we create a button that calls the "IsItDead" method. If we do not have a memory leak then the method should return "Still here" while the window is open and "I 'm dead" a while after the window is closed.

You can download the demo project here

Posted: Κυριακή, 26 Μαΐου 2013 5:31 μμ από iwannis | 0 σχόλια
Δημοσίευση στην κατηγορία: ,
Handling errors and internet connectivity problems in Windows 8 Apps with navigation (WinJS)

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.

Posted: Παρασκευή, 24 Μαΐου 2013 3:57 μμ από iwannis | 0 σχόλια
Δημοσίευση στην κατηγορία: ,