WebClient change for Mango, how it impacts your application ?

You, in this case is a developer who has published or will publish a Windows Phone 7.0/7.1 app.

In WP7.0 we had recommended HttpWebRequest over WebClient in our ListBox scrolling post for WP7. Reason for recommending that was, in WP7.0, if the developer created a WebClient request from background thread (any thread actually), the response would always come back to the UIthread. This was causing unexpected heavy processing operations to happen on the UIthread, causing interactivity issues. So we recommended using HttpWebRequests. In HttpWebRequests, the response would come back on the thread where the request originated.

In Mango, 7.1 apps, we fixed the WebClient issue. So now, a WebClient request created from background thread will receive the response on the same thread. However, if the request is created on the UIthread, the response will come back on the UIthread, this is not recommended. Keeping the UIthread free from heavy processing should be the goal.

How does this impact your application on upgrade from 7.0 to 7.1?

If in 7.0 app, you have an application that created a WebClient request on background thread. Received the response on the UIThread (to update properties on the UI, example add item to your ObservableCollection, bound to ListBox or updated Text of a TextBlock), then on upgrade to 7.1 and running the application as is, will cause

System.UnauthorizedAccessException: Invalid cross-thread access error

You developed your app with an assumption that the response will come back on the UIThread. However, with this change, the response will go back on the background thread causing the cross-thread access error.

Let us look at an example:

Attached is a 7.0 app, where we make a WebClient request on BackgroundWorker thread using Bing Image APIs and get a response back on the UIthread.

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
       {
           //in a real world scenario this is something where heavy lifting happens on a 
 background thread 
  WebClient wc = new WebClient();
           wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
           UriBuilder fullUri = new UriBuilder("https://api.bing.net/xml.aspx?");
           // Common request fields (required) fullUri.Query = "AppId=XXXXXX" + "&Query=" + _searchterm
           + "&Sources=Image";
           wc.OpenReadAsync(fullUri.Uri);
       }
  

Then we update the UI after we received the response. Highlighted is the UIthread action.

 

 void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
       {
           Stream streamResult = e.Result;
           XElement xmlBingImages = XElement.Load(streamResult);
           string mms = "https://schemas.microsoft.com/LiveSearch/2008/04/XML/multimedia";
           var TEMP = xmlBingImages.DescendantNodes();           
           int totalResults = Convert.ToInt32(xmlBingImages.Descendants("{" + mms + "}Total").First().Value);
           

WebClientSampleText.Text = "Total# of Bing image results: "+totalResults.ToString();

             
       }
 

As an exercise, right click on the project from VS2010, upgrade to 7.1

Debug the application. You will see the following exception

 

image

 

And this is how we work around it

 Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                WebClientSampleText.Text = "Total# of Bing image results: " + totalResults.ToString();
            });
 

Goal of this post is to inform the developers(upgrading from 7.0 to 7.1) about this possible change, they will have to make, if they run into the cross-thread access error.

Thanks

[PS: This was published initially with some glaring grammar mistakes, sorry about that. Was published in a hurry. Got the feedback. It wont be 100% perfect grammatically, but I will try better next time.  Constructive criticism is appreciated.]

WebClient70Sample.zip