BugAid, a Visual Studio debugger add-on. A quick review.

 

bugaid

 

I spend a lot of development time in Visual Studio (VS) and I am a fan of using any product which increases my productivity and makes my work more fun. That's why I use products like Resharper, Tabs Studio & Mole 2010. These are commercial products I purchased. I also use some free add-ons like RightHand Dataset Visualizer which is the best dataset visualizer around. (Even though it's 35M! The author uses third party components which are packaged into a single dll)

 

Recently I came across a new add-on called BugAid from bugaidsoftware.com. It's an add-on for Visual Studio's debugger inline watch and adds some nice features to it. It's still in beta and this review is based on version 0.5.1206.6134_456.

 

Some of the features which BugAid adds:

  • Star important members. Show properties you're interested in at the top of the watch window including properties from base classes. More...
separator

Using .NET Task Parallel Library (TPL) to run parallel tasks and update UI controls. Includes sample app.

When analyzing a programming task requirement, one of the questions a good developer asks themselves is if there’s any subtask which can be run in the background or asynchronously. For example, If a task needs to get data from two independent data sources, there’s really no need to run these two data retrieval tasks in sequence. The app would be faster and more scalable if these tasks run in parallel instead of in sequence.

In .NET it is customary to run these tasks in new threads. The BackgroundWorker class is also a way to do this asynchronously.

In .NET 4.0 there’s a new class library called the Task Parallel Library (TPL) which offers an abstraction over the creation and use of threads. TPL enables the use of multicore machines without worrying about coding details.

In this post, I will not get into detail about TPL and how it works. I will be showing an example of how to fire off two parallel tasks to simulate grabbing of data, showing how to update UI controls from a non UI thread and how to return data from these tasks.

I have a WinForm form which contains 3 buttons and a few textboxes and labels to display a task status and the data retrieved.

There are two identical tasks, each simulate retrieving a customer’s data from a source and returning the customer data to the UI. Each task is constructed in a way where it retrieves the data, displays its status, returns the data to the UI and the UI displays the data. Each task can be launched at any time independent of the other task, both can be launched simultaneously and the UI is still responsive.

Note: a thread can not update a UI control which was not created in the same thread.

 

Steps to create a task so it can launched in parallel or asynchronously & be able to update a UI control:

  1. Get a reference to the UI’s TaskScheduler. This is used for the initial task’s continuation. The continuation task is where the data is displayed.

  2. Get the current UI SynchronizationContext. We need this context to post a UI control update in the initial task (changing text in a textbox). Remember this task is running in a different thread than the UI thread. A non UI thread can not update a UI control. Because this is a non UI thread, anything happening here will not block the UI thread, freeing the UI to be responsive to user actions.

  3. Create and start a new Task. Inside this task the following happens:
    Update a textbox to display task’s status. Here we simulate a slow running process. This can be for example a web service which returns a customer data.

  4. A continuation task for the initial task runs when the initial task completes. This task is able to update UI controls because it’s using the UI’s TaskScheduler.

 

The steps above can be repeated for as many tasks as needed to run in parallel. There are TPL’s methods to wait for any or all of these tasks to complete before another continuation task uses their data. There are also methods for cancellations, exception handling, waiting plus more. I won’t be discussing these here. The TPL’s reference on Microsoft’s site has detailed information.

 

Proof that non UI threads can not update UI controls:

If you uncomment the statement which updates the textbox’s text from inside the task inside Visual Studio’s debugger, an InvalidOperation exception occurs with message “Cross-thread operation not valid: Control 'txtTask1' accessed from a thread other than the thread it was created on.”. However I am not sure why it works in non debugger mode. Always use post or use BeginInvoke to update UI controls from non UI threads.

 

The code below shows the form’s code. You can also download the Visual Studio project. ParallelDemo using TPL.zip (56.32 kb)

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
        }

        private void btnTask1_Click(object sender, EventArgs e)
        {
            GetCustomer1();
        }

        private void GetCustomer1()
        {
            int customerID = 1;
            lblFirstName1.Text = "";
            lblLastName1.Text = "";
            var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

            SynchronizationContext synContext = SynchronizationContext.Current;

            Task<Customer> customerTask = Task.Factory.StartNew(() =>
                                                                    {
                                                                       // txtTask1.Text = "Running for 5 seconds...";
                                                                        synContext.Post(
                                                                            state => txtTask1.Text = (string) state,
                                                                            "Running for 4 seconds...");
                                                                        Customer newCustomer = new Customer();
                                                                        newCustomer.CustomerID = customerID;
                                                                        newCustomer.FirstName = "John";
                                                                        newCustomer.LastName = "Smith";
                                                                        Thread.Sleep(4000);
                                                                        return newCustomer;
                                                                    });


            customerTask.ContinueWith(t =>
                                          {
                                              lblFirstName1.Text = "First name: " + t.Result.FirstName;
                                              lblLastName1.Text = "Last name: " + t.Result.LastName;
                                              txtTask1.Text = "Done.";
                                          }, uiScheduler);
        }


        private void button2_Click(object sender, EventArgs e)
        {
            GetCustomer2();
        }


        private void GetCustomer2()
        {
            int customerID = 2;
            lblFirstName2.Text = "";
            lblLastName2.Text = "";
            var uiScheduler =
                TaskScheduler.FromCurrentSynchronizationContext();

            CancellationTokenSource tokenSource
                = new CancellationTokenSource();

            // create the cancellation token 
            CancellationToken cancellationToken = tokenSource.Token;
            SynchronizationContext synContext = SynchronizationContext.Current;


            Task<Customer> customerTask = Task.Factory.StartNew(() =>
                                                                    {
                                                                        /* txtTask2.Text =  "Running for 5 seconds...";*/
                                                                        synContext.Post(
                                                                            state => { txtTask2.Text = (string) state; },"Running for 5 seconds...");
                                                                        Customer newCustomer = new Customer();
                                                                        newCustomer.CustomerID = customerID;
                                                                        newCustomer.FirstName = "Jane";
                                                                        newCustomer.LastName = "Doe";
                                                                        Thread.Sleep(5000);
                                                                        return newCustomer;
                                                                    });


            customerTask.ContinueWith(t =>
                                          {
                                              lblFirstName2.Text = "First name: " + t.Result.FirstName;
                                              lblLastName2.Text = "Last name: " + t.Result.LastName;
                                              txtTask2.Text = "Done.";
                                          }, uiScheduler);
        }


        private void btnStartAll_Click(object sender, EventArgs e)
        {
            GetCustomer1();
            GetCustomer2();
        }
    }


    public class Customer
    {
        public int CustomerID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
separator

Using .NET Task Parallel Library (TPL) to run parallel tasks and update UI controls. Includes sample app.

When analyzing a programming task requirement, one of the questions a good developer asks themselves is if there’s any subtask which can be run in the background or asynchronously. For example, If a task needs to get data from two independent data sources, there’s really no need to run these two data retrieval tasks in sequence. The app would be faster and more scalable if these tasks run in parallel instead of in sequence.

In .NET it is customary to run these tasks in new threads. The BackgroundWorker class is also a way to do this asynchronously.

In .NET 4.0 there’s a new class library called the Task Parallel Library (TPL) which offers an abstraction over the creation and use of threads. TPL enables the use of multicore machines without worrying about coding details.

In this post, I will not get into detail about TPL and how it works. I will be showing an example of how to fire off two parallel tasks to simulate grabbing of data, showing how to update UI controls from a non UI thread and how to return data from these tasks.

I have a WinForm form which contains 3 buttons and a few textboxes and labels to display a task status and the data retrieved.

There are two identical tasks, each simulate retrieving a customer’s data from a source and returning the customer data to the UI. Each task is constructed in a way where it retrieves the data, displays its status, returns the data to the UI and the UI displays the data. Each task can be launched at any time independent of the other task, both can be launched simultaneously and the UI is still responsive.

Note: a thread can not update a UI control which was not created in the same thread.

 

Steps to create a task so it can launched in parallel or asynchronously & be able to update a UI control:

  1. Get a reference to the UI’s TaskScheduler. This is used for the initial task’s continuation. The continuation task is where the data is displayed.

  2. Get the current UI SynchronizationContext. We need this context to post a UI control update in the initial task (changing text in a textbox). Remember this task is running in a different thread than the UI thread. A non UI thread can not update a UI control. Because this is a non UI thread, anything happening here will not block the UI thread, freeing the UI to be responsive to user actions.

  3. Create and start a new Task. Inside this task the following happens:
    Update a textbox to display task’s status. Here we simulate a slow running process. This can be for example a web service which returns a customer data.

  4. A continuation task for the initial task runs when the initial task completes. This task is able to update UI controls because it’s using the UI’s TaskScheduler.

 

The steps above can be repeated for as many tasks as needed to run in parallel. There are TPL’s methods to wait for any or all of these tasks to complete before another continuation task uses their data. There are also methods for cancellations, exception handling, waiting plus more. I won’t be discussing these here. The TPL’s reference on Microsoft’s site has detailed information.

 

Proof that non UI threads can not update UI controls:

If you uncomment the statement which updates the textbox’s text from inside the task inside Visual Studio’s debugger, an InvalidOperation exception occurs with message “Cross-thread operation not valid: Control 'txtTask1' accessed from a thread other than the thread it was created on.”. However I am not sure why it works in non debugger mode. Always use post or use BeginInvoke to update UI controls from non UI threads.

 

The code below shows the form’s code. You can also download the Visual Studio project. ParallelDemo using TPL.zip (56.32 kb)

   1: public partial class Form1 : Form
   2:     {
   3:         public Form1()
   4:         {
   5:             InitializeComponent();
   6:             
   7:         }
   8:  
   9:         private void btnTask1_Click(object sender, EventArgs e)
  10:         {
  11:             GetCustomer1();
  12:         }
  13:  
  14:         private void GetCustomer1()
  15:         {
  16:             int customerID = 1;
  17:             lblFirstName1.Text = "";
  18:             lblLastName1.Text = "";
  19:             var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  20:  
  21:             SynchronizationContext synContext = SynchronizationContext.Current;
  22:  
  23:             Task<Customer> customerTask = Task.Factory.StartNew(() =>
  24:                                                                     {
  25:                                                                        // txtTask1.Text = "Running for 5 seconds...";
  26:                                                                         synContext.Post(
  27:                                                                             state => txtTask1.Text = (string) state,
  28:                                                                             "Running for 4 seconds...");
  29:                                                                         Customer newCustomer = new Customer();
  30:                                                                         newCustomer.CustomerID = customerID;
  31:                                                                         newCustomer.FirstName = "John";
  32:                                                                         newCustomer.LastName = "Smith";
  33:                                                                         Thread.Sleep(4000);
  34:                                                                         return newCustomer;
  35:                                                                     });
  36:  
  37:  
  38:             customerTask.ContinueWith(t =>
  39:                                           {
  40:                                               lblFirstName1.Text = "First name: " + t.Result.FirstName;
  41:                                               lblLastName1.Text = "Last name: " + t.Result.LastName;
  42:                                               txtTask1.Text = "Done.";
  43:                                           }, uiScheduler);
  44:         }
  45:  
  46:  
  47:         private void button2_Click(object sender, EventArgs e)
  48:         {
  49:             GetCustomer2();
  50:         }
  51:  
  52:  
  53:         private void GetCustomer2()
  54:         {
  55:             int customerID = 2;
  56:             lblFirstName2.Text = "";
  57:             lblLastName2.Text = "";
  58:             var uiScheduler =
  59:                 TaskScheduler.FromCurrentSynchronizationContext();
  60:  
  61:             CancellationTokenSource tokenSource
  62:                 = new CancellationTokenSource();
  63:  
  64:             // create the cancellation token 
  65:             CancellationToken cancellationToken = tokenSource.Token;
  66:             SynchronizationContext synContext = SynchronizationContext.Current;
  67:  
  68:  
  69:             Task<Customer> customerTask = Task.Factory.StartNew(() =>
  70:                                                                     {
  71:                                                                         /* txtTask2.Text =  "Running for 5 seconds...";*/
  72:                                                                         synContext.Post(
  73:                                                                             state => { txtTask2.Text = (string) state; },"Running for 5 seconds...");
  74:                                                                         Customer newCustomer = new Customer();
  75:                                                                         newCustomer.CustomerID = customerID;
  76:                                                                         newCustomer.FirstName = "Jane";
  77:                                                                         newCustomer.LastName = "Doe";
  78:                                                                         Thread.Sleep(5000);
  79:                                                                         return newCustomer;
  80:                                                                     });
  81:  
  82:  
  83:             customerTask.ContinueWith(t =>
  84:                                           {
  85:                                               lblFirstName2.Text = "First name: " + t.Result.FirstName;
  86:                                               lblLastName2.Text = "Last name: " + t.Result.LastName;
  87:                                               txtTask2.Text = "Done.";
  88:                                           }, uiScheduler);
  89:         }
  90:  
  91:  
  92:         private void btnStartAll_Click(object sender, EventArgs e)
  93:         {
  94:             GetCustomer1();
  95:             GetCustomer2();
  96:         }
  97:     }
  98:  
  99:  
 100:     public class Customer
 101:     {
 102:         public int CustomerID { get; set; }
 103:         public string FirstName { get; set; }
 104:         public string LastName { get; set; }
 105:     }
separator

Size of Silverlight browser plugin should not be an issue

Once a while I hear/read about some people criticizing the size of the Silverlight plugin as if the size is a roadblock to its use. I don’t understand what the issue is. The size, about 6 megs, is comparable to Flash’s size yet I don’t hear people complaining about Flash’s size.  What is 6 megs in this era of drives whose capacity is measured in hundreds of gigabytes and terabytes? Most people have broadband and 6 megs is downloaded in a few seconds. The plugin is downloaded only once and unless there’s an updated version, hitting any Silverlight site will not re-download the plugin.

If you look closely at the types of sites that require Silverlight, they are mostly games and streaming video sites. The type of apps which require a lot of disk space and broadband connectivity in the first place. So these type of users won’t blink for a tiny plugin. If a user doesn’t mind downloading the Flash plugin, why should Silverlight be any different? The other type of Silverlight applications are the Line of Business ones used inside an organization where network connectivity is very fast.

So… people… there are lots of more important issues to worry about!

separator