SharpGIS

#GIS from a .NET developer's perspective

WinRT vs. Silverlight - Part 7 - Making WebRequests

See intro blogpost here.

In Silverlight and WPF you are probably used to using WebClient to perform downloads. This is a simple class for doing download/upload string or retrieving a response stream from the server. However, in Windows Runtime this client doesn’t exists. Instead we have new a simple “HttpClient” to do much of what WebClient can. However it works very differently by using the new Task framework, and the more you dive into porting code to WinRT, you will see this a lot, and it will make your life porting code cumbersome. On the upside, the Tasks framework is awesome and it’ll often simplify you code a great deal! I talked a bit about this in my previous post, so please read that first, before you continue here, since this will be building on top of that.

Let’s say we have a method in WPF and Silverlight that uses WebClient to downloada and create an image. Since this is working asynchronously, we would have to either use event handlers or action delegates to return the result and/or the error. The method could look something like this:

public void GetContent(Uri uri, Action<string> complete, Action<Exception> error)
{
    WebClient client = new WebClient();
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
            error(e.Error);
        else {
            complete(e.Result);
        }
    };
    client.DownloadStringAsync(uri);
}

 

Here’s how a method like that could look in WinRT:

public async Task<string> GetContentI(Uri uri)
{
   System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
   var result = await client.GetAsync(uri);
   return result.Content.ReadAsString();
}

Simple right? Well it' gets even simpler when we have to start consuming that method.

From SL and WPF you would consume the method something like this:

GetContent(uri, (text) => {
          TextBlock tb = new TextBlock() { Source = text };
          LayoutRoot.Children.Add(tb);
      },
      (error) => { /*TODO: handle error*/ }
);

And the same using the Task framework:

try {
   TextBlock tb = new TextBlock() { Source = await GetContent(uri) };
   LayoutRoot.Children.Add(tb);
catch { /*TODO: handle error */ }

You tell me what’s more elegant and readable? Smile

My point here is that Tasks are awesome, so rather than trying to reuse your existing code in WinRT, consider rewriting your existing code to use Tasks and it will work much smoother.

There’s lets create a method for downloading a string over the network that works the same way across the board. (I’ll assume you are using the Async Task CTP for Silverlight or WPF for this).

public async Task<string> GetContent(Uri uri)
{
#if NETFX_CORE
    System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
    var reqResult = await client.GetAsync(uri);
    return reqResult.Content.ReadAsString();
#else
    WebClient client = new WebClient();
    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
    client.DownloadStringCompleted += (sender, e) =>
    {
        if (e.Error != null)
            tcs.TrySetException(e.Error);
        else
            tcs.TrySetResult(e.Result);
    };
    client.DownloadStringAsync(uri);
    return await tcs.Task;
#endif
}

Note you could also use the new .NET method “WebClient.DownloadStringTaskAsync” which would simplify the above quite a lot. I used the event based approach to demonstrate how you would handle the cases where you don’t already have a task implementation available.

WinRT vs. Silverlight - Part 6 - Using Tasks

See intro blogpost here.

When you start working with WinRT, you start seeing classes missing or changed. A lot of methods are now only asynchronous, like making a web request, opening, reading and writing files etc. They all now on the Task framework, and they do this to ensure you application is always responsive. However without this framework, it would be a pain to code against an API that’s inherently asynchronous all the way through. But with it, it makes it really easy to write code against it.

As an example here’s how you normally write async operations in WPF and Silverlight:

var myObject = new MyClass();
myObject.Completed += (sender,e) => { 
   //Completed event handler 
if(e.Error == null) { statusText.Text = "My Operation has completed: " + e.Result;
} }; myObject.StartAsync(); //Starts process and fires "Completed" event when done

So we first hook up to the event handler, then call start. When you look at the code, the lines are not executed in the order they are written. The completed delegate executes after the operation completes after Start() has been run (even explaining it makes it sound confusing). Also you cannot throw exceptions from an asynchronous running process, because there will be no way to catch it, so you’ll have to parse an exception object back as part of your result and check it.

This pattern makes it hard to read and understand the code, since it’s not immediately obvious what code runs when. Especially when the code gets more complex and/or your eventhandlers are declared elsewhere. When we then nest events, it gets very convoluted quickly:

var myObject = new MyClass();
myObject.Completed += (sender,e) => { 
   if(e.Error == null) {
       //Perform next operation
       var myObject2 = new MyClass();
       myObject2.Completed += (sender2,e2) => { 
           if(e2.Error == null) {
              //Completed event handler
              statusText.Text = "My Operation has completed: " + e2.Result;
} }; myObject2.StartAsync(); } }; myObject.StartAsync();

With the Task framework this becomes very simple and straightforward to write and more importantly read:

var myObject = new MyClass();
try {
     string result = await myObject.StartAsync();
     var myObject2 = new MyClass();
     string result2 = await myObject2.StartAsync();
     statusText.Text = "My Operation has completed: " + result2;
} catch { }

Notice that we don’t bother with checking an error object. We simply use try/catch instead, and the task returns the result up front. If it wasn’t for the little “await” keyword, it looks like this is just good ol’ synchronous programming! This is pure awesomeness!

If you are planning on porting a large application from Silverlight or WPF and it uses a lot of event-based asynchronous programming, you are probably in for some work. Not to say that your application can’t use events, but a lot of the WinRT API’s don’t have eventhandlers any more, so if you insist on keeping it this way, you would have to wrap all the built in tasks into some event-based classes. I would probably rather focus on moving forward and getting this cleaned up. And since the Task framework is already available in .NET 4 and there’s a CTP for Silverlight (and included in upcoming v5!) and WinPhone, you could port your original code to start taking advantage of this, making your code reuse easier and cleaner moving forward.

So how would you go about wrapping an event-based class into a task based method? Well let’s continue using the MyClass example above, and wrap it in a task. Here’s how that would look:

public Task<string> StartAsync()
{
    var tcs = new TaskCompletionSource<string>();
    var obj = new MyClass();
    obj.Completed += (sender,e) => {
        if (e.Error != null)
              tcs.TrySetException(e.Error);
        else
              tcs.TrySetResult(e.Result);
    };
    obj.StartAsync();
    return tcs.Task;
}

Basically we return Task of string, instead of just a string. We use the TaskCompletionSource of string to handle error and result messaging back to the task.

So when should you make a method an asynchronous task? The rule of thumb is: If it takes more than 50ms to execute, it should be asynchronous! This helps a lot towards preventing the UI from becoming choppy and/or unresponsive.

WinRT vs. Silverlight - Part 5 - Defining default style template

See intro blogpost here.

Here's something that's actually NOT different in Silverlight (but it's different from WPF as it has always been).
You declare your style using DefaultStyleKey. This means the code looks like this for Silverlight, WPF and Windows Runtime:

public class MyControl : Control
{
    public MyControl()
    {
#if SILVERLIGHT || NETFX_CORE
        this.DefaultStyleKey = typeof(MyControl);
#endif
    }
    static MyControl() {
#if !SILVERLIGHT && !NETFX_CORE
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(HoverControl),
            new FrameworkPropertyMetadata(
            typeof(HoverControl))); 
#endif
    }
}

Here is what IS different though: You need to set the build action of \Themes\Generic.xaml to "Content". It won't work without it.
Also note that when you add Generic.xaml to your project, it will also get added to App.Xaml. I assume this is a bug in the current release, but you will have to go and delete this entry, or it won't work.

WinRT vs. Silverlight - Part 4 - Dispatcher

See intro blogpost here.

In Silverlight and WPF you will often use the Dispatcher to return from a background thread to jump to the UI Thread. This is required when you need to update your UI, because you’re not allowed to touch the UI from anything but the UI Thread. The Dispatcher method has changed slightly in WinRT. It’s also now of type “CoreDispatcher”, instead of just “Dispatcher”.

#if !NETFX_CORE
  Dispatcher.BeginInvoke(
#else
  Dispatcher.Invoke(CoreDispatcherPriority.Normal, 
#endif
           (s, a) => { ... }
#if NETFX_CORE
      , this, null);
#endif
   );

WinRT vs. Silverlight - Part 3 - Dependency Properties

See intro blogpost here.

UPDATE Feb. 29, 2012: As hinted at below that this would happen, this blogpost on dependency properties is now outdated. Since the Consumer Preview of Windows 8 released, dependency properties now work exactly like they do in Silverlight and WPF.

---

Declaration of dependency properties has changed in the WinRT. This is a temporary change and will go away when WinRT hits beta, but still good to know if you start prototyping on WinRT today. If you are a control developer this is probably one of the things you would have to change in the most places.

Here’s what the API looks like for Silverlight and WPF for registering a Dependency Property or an Attached Property:

public static DependencyProperty Register(
      string name, 
      Type propertyType, 
      Type ownerType,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      Type propertyType,
      Type ownerType, 
      PropertyMetadata defaultMetadata);

And here’s what this currently looks like in WinRT CTP :

public static DependencyProperty Register(
      string name, 
      string propertyTypeName, 
      string ownerTypeName,
      PropertyMetadata typeMetadata);
public static DependencyProperty RegisterAttached(
      string name, 
      string propertyTypeName,
      string ownerTypeName, 
      PropertyMetadata defaultMetadata);

Notice how the PropertyType and PropertyOwnerType is now strings instead of types!

This means you would have to write your code like this to make it cross-compile:

        public double MyDoubleProperty
        {
            get { return (double)GetValue(MyDoublePropertyProperty); }
            set { SetValue(MyDoublePropertyProperty, value); }
        }

        public static readonly DependencyProperty MyDoublePropertyProperty =
            DependencyProperty.Register("MyDoubleProperty", 
#if NETFX_CORE
             "Double", "MyNamespace.MyControl", 
#else
                typeof(double), typeof(MyNamespace.MyControl), 
#endif
                 new PropertyMetadata(0d));

Also note that you don’t use the full type name for the system types. Ie. here you use “Double” and not “double” or “System.Double”.

You could create a few static methods to replace the Register/RegisterAttached methods that will make your code cross-platform, and switch it out just there when this changes. Here’s one example how this could be accomplished (the ‘ToRTString’ method isn’t fully tested though…):

    public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.RegisterAttached(name, 
#if NETFX_CORE
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
    public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata metadata)
    {
        return DependencyProperty.Register(name,
#if NETFX_CORE
            propertyType.ToRTString(), ownerType.ToRTString()
#else
            propertyType, ownerType
#endif
            , metadata);
    }
#if NETFX_CORE
    private static string ToRTString(this Type type)
    {
        string name = type.FullName;
        if(name.StartsWith("System."))
            return name.Substring(7);
        else
            return name;
    }
#endif

WinRT vs. Silverlight - Part 2 - Code Namespace

See intro blogpost here.

The namespaces in WinRT has changed for all the UI related classes. Generally System.Windows has been replaced with Windows.UI.Xaml, and the rest is the same below that. If we to use the “NETFX_CORE” compiler directive that WinRT projects comes with, the typical default using statements that would compile on both Silverlight, WPF and WinRT would look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if !NETFX_CORE
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;
#endif

This is also described in greater detail here: http://msdn.microsoft.com/en-us/library/windows/apps/hh465136(v=VS.85).aspx

WinRT vs. Silverlight - Part 1 - XML Namespace

See intro blogpost here.

For the most part your XAML ports right over to WinRT. However an important change is how you register namespaces from your assemblies.

Here's how you do this in Silverlight and WPF for an assembly "MyAssembly.dll" and namespace MyAssembly.MyNamespace:

    xmlns:local="clr-namespace:MyAssembly.MyNamespace;assembly:MyAssembly"

And similar for namespaces in the same assembly as where the XAML file lives (ie MyAssembly):

    xmlns:local="clr-namespace:MyAssembly.MyNamespace"

In WinRT, you only declare the namespace (never the assembly) and instead use "using" instead of "clr-namespace":

    xmlns:local="using:MyAssembly.MyNamespace"

Unfortunately we don't have #if-def statements in XAML so you can just use compiler directives on your XAML and make it work on both platforms. So until we get that (or Microsoft reverts the above change) you are going to have to duplicate and maintain two sets of XAML. :-(

I actually do like this change, and this is probably how it should always have been, but it's a change that cause a lot of pain for developers trying to reuse their existing codebase. The benefit doesn't seem to pain (from what I understand the Windows team simply didn't like it said "clr" in there, plus they don't have the exact same concepts down in the runtime so the assembly part was left out.)

WinRT vs. Silverlight - Part 0

I recently wrote a blog post series on how to share your code between Silverlight and WPF.

With the announcements of Windows 8 at the //BUILD/ conference and the new Windows Runtime (WinRT) which can be built against using C# and XAML I thought it appropriate to start a new series on how to make your existing Silverlight/WPF code run on WinRT. I'm mostly writing this as notes to myself and hope you will also find them useful. Personally I've already found a lot of issues with porting code over. Not that there are significant changes, but the documentation is very limited at this point, and the gotchas enough to make you waste a lot of time on resolving this. Hopefully this will act as a resource to get it working for you as well. Keep an eye on this post. I'll post new links as I go along learning new things about WinRT.

Generally what I have found is that with respect to XAML WinRT is more compatible to Silverlight than WPF, so expect it easier to use your Silverlight knowledge, and don't try and use WPF XAML features at this point. Things like DataTriggers etc. are not supported, and for the most part, the UI related methods in code are more similar to Silverlight than .NET 4 (note however that non-UI code is closer to the "original" .NET, since this is essentially the same CLR and compiler used).

I won't go into too much detail about what this means for Silverlight and WPF. There's plenty of blogs and newssites that has their (over?)reactions described in detail. This series will really just focus on how to take your existing code and get it running on WinRT.

Click to select a topic below:

  1. WinRT vs. Silverlight - Part 1 - XML Namespace
  2. WinRT vs. Silverlight - Part 2 - Code Namespace
  3. WinRT vs. Silverlight - Part 3 - Dependency Properties
  4. WinRT vs. Silverlight - Part 4 - Dispatcher
  5. WinRT vs. Silverlight - Part 5 - Defining default style template
  6. WinRT vs. Silverlight - Part 6 - Using Tasks
  7. WinRT vs. Silverlight - Part 7 - Making WebRequests 
  8. WinRT vs. Silverlight - Part 8 - What other people are blogging
  9. Coming… WinRT vs. Silverlight - Part 9 - File IO
  10. Coming… WinRT vs. Silverlight - Part 10 – Various CTP bugs…
  11. More…

GZIP Compressed Web Requests in WP7 - Take 2

I earlier wrote about how .NET API in Windows Phone 7 doesn’t zip-compress it’s web requests, and how using Mango’s socket support allows you to circumvent that to get more efficient use of the limited data connection phones often have. The approach had some problems and limitations, and wouldn’t work in all scenarios. Even so, compressing your webrequests is very important on a phone since you can often save 50-80% of the data transmitted, and many people pay by the byte they transmit.

Since my blogpost Windows Phone 7 Mango has gone through a few iterations, and using a socket is no longer necessary, since the “accept-encoding” header needed to request GZIP compressed requests is no longer blocked (thank you to those who voted for getting this unblocked). However, GZIP compression is still not a built in feature (Why not Microsoft?!?). If you set this header, you are still in charge of uncompressing the content. I’ve updated my GZipWebClient class to take advantage of the new allowed header. It simplifies the class quite a lot, as well as made it more stable.

Also I “forked” the DotNetZip library and included in this project, so you don’t need to go find 3rd party dependencies, and in the process removed all parts of the library that is not needed to keep the assembly as compass as possible. So here’s what the client now basically looks like:

public class GZipWebClient : WebClient
{
    [SecuritySafeCritical]
    public GZipWebClient()
    {
    }
    protected override WebRequest GetWebRequest(Uri address)
    {
        var req = base.GetWebRequest(address);
        req.Headers[HttpRequestHeader.AcceptEncoding] = "gzip"; //Set GZIP header
        return req;
    }
    protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
    {
        WebResponse response = null;
        try
        {
            response = base.GetWebResponse(request, result);
            if (response.Headers[HttpRequestHeader.ContentEncoding] == "gzip")
                return new GZipWebResponse(response); //If gzipped response, uncompress
            else
                return response;
        }
        catch
        {
            return null;
        }
    }
}

The key here is adding the header that tells the server “Hey I understand GZipped responses as well”. When the response comes back and the header says “Hey here’s some gzipped content”, I use a custom GzipWebResponse class that uses the DotNetZip library to uncompress the stream. Apart from some trivial code, this is the meat of that class:

internal class GZipWebResponse : WebResponse
{
    WebResponse response;
    internal GZipWebResponse(WebResponse resp)
    {
        response = resp;
    }
    public override System.IO.Stream GetResponseStream()
    {
        return new SharpGIS.ZLib.GZipStream(response.GetResponseStream()); //Uncompress
    }
}

You use it exactly like the normal “WebClient” class, except you instantiate the GZipWebClient instead. The rest of your existing code doesn’t change at all. Example:

WebClient client = new SharpGIS.GZipWebClient();
client.DownloadStringCompleted += client_DownloadStringCompleted;
client.DownloadStringAsync(uri);

You can download the source code below, and you can also get it on NuGet/SymbolSourceusing command “Install-Package SharpGIS.GZipWebClient”

Download source

I also rely heavily on this in my WinPhone Twitter client ‘Peregrine’ and have seen quite a performance improvement when updating your twitter timeline. You can download Peregrine for free here: http://www.windowsphone.com/en-us/apps/75067abc-c9d1-47b7-8ace-76aede3911b2?wa=wsignin1.0

UPDATE!!!

With the latest v1.1 update on nuget (source also updated here), you don’t have to do the above. All you need to write is the following two lines of code and put it in your app.xaml.cs startup file. After this ALL existing code (including 3rd party libraries you don’t have control over) will start using GZIP compression!

WebRequest.RegisterPrefix("http://", SharpGIS.WebRequestCreator.GZip);
WebRequest.RegisterPrefix("https://", SharpGIS.WebRequestCreator.GZip);

If you just want to do this for some domains, only register that prefix part. So no need to go replace all your WebClient as mentioned above. More on how this work in this blogpost.

UPDATE2!!!

Note that using RegisterPrefix causes this to use an internal custom HttpWebRequest class and that can have some serious effects on your app. Unfortunately Microsoft ‘forgot’ to unlock the Get/Set UserAgent property when they ported from Silverlight (there the user agent was always the browser), and many 3rd party libraries  tries to set this property, which will throw a NotImplementedException. Also note that cookies are not supported either (some libraries use that). They should of course be checking the “SupportsCookieContainer” property before using it, but not all do (I’m looking at you RestSharp), and will therefore throw an exception. However for almost all the simpler scenarios, the above register works like a charm.

UPDATE3!!!

Now also on GitHub: https://github.com/dotMorten/SharpGIS.GZipWebClient

UPDATE4!!!

Update 2 no longer applies :)

Windows Phone: Adding Mango features to a 7.0 WinPhone App

Microsoft just announced what happens to your non-Mango app (WP7.0) if you publish a Mango app (WP7.1) to the marketplace. Basically if you upgrade your app to 7.1, you will no longer be able to maintain the 7.0 app for people who still haven’t upgraded yet (and we know from the last update that that can take a while).

However, it is possible to make a 7.0 app that uses Mango features if the user has upgraded to Mango. That way you can continue to build a 7.0 app, and the moment the user upgrades to Mango, he will get additional features available. All this using a little “reflection magic”. The certification requirements does kind of hint at that this is not allowed, but some apps has already made it through certification, so this seems to be considered OK to do, and it also works great as well.

So how is this done? We can use the method of the Type object to get identifiers of methods, events, constructors, properties etc. by using their names. This way we will never write a piece of code that explicitly uses one of these (which the compiler would reject), but instead at runtime will attempt to locate them, and if successful execute/access it

But before we attempt doing that, we can perform a check for whether this is a mango device (or newer). Mango is v7.1, so it must be version 7.1 or newer:

bool IsMangoDevice = (Environment.OSVersion.Version >= new Version(7, 1));

We can also get access to types we don’t have yet in the 7.0 compiler but the 7.1 device has. For example, the StandardTileData class used to create secondary tiles for your app can be accessed using its full name and assembly:

Type t = Type.GetType("Microsoft.Phone.Shell.StandardTileData, Microsoft.Phone");

If we continue down this path, we can actually create a secondary tile on a mango device, and still have the app be 7.0. That means you can TODAY submit an app to the marketplace that uses mango features, and people with developer devices will get mango features now! (again note that this might cause problems during marketplace certification, but some apps has already made it through and is available today!)

Anyway… here’s the code that creates a secondary tile:

//get the constructor for the StandardTileData and create a new instance of it
var newTileData = t.GetConstructor(new Type[] { }).Invoke(null);
//Get the setter method for the title property
var setMethod = newTileData.GetType().GetProperty("Title").GetSetMethod();
//Set the tile title
setMethod.Invoke(newTileData, new object[] { "This is my new tile" });
//Get the create method for the shell tiles
Type shellTileType = Type.GetType("Microsoft.Phone.Shell.ShellTile, Microsoft.Phone");
var createMethod = shellTileType.GetMethod("Create");
//Create the tile, with the uri and tile data
Uri uri = new new Uri("/MainPage.xaml?Test=This_Came_From_A_Secondary_Tile", UriKind.Relative)
createMethod.Invoke(null, new object[] {  uri, newTileData});

Or how about setting the system tray color?

typeof(Microsoft.Phone.Shell.SystemTray).GetProperty("BackgroundColor").
GetSetMethod().Invoke(null, new object[] { Colors.Red });

Of course you should only call these methods if the device is a mango device, so use the check shown first before executing this code. I created an extension class that neatly encapsulates this and only executes the code if it’s supported. Examples:

//Set tray color if supported
MangoExtensions.SetTrayColor(Colors.Blue);

//Add hold event handler to a control (onHold is of type RoutedEventHandler delegate):
myControl.AddEventHandler_Hold(onHold);

//Show "Create secondary tile" button if supported:
createTileButton.Visibility = MangoExtensions.IsMangoDevice ? Visibility.Visible : Visibility.Collapsed;

//Create/replace tile:
MangoExtensions.CreateTile("My Tile", new Uri("/MainPage.xaml?parameter1=value1", UriKind.Relative));

You can download the entire extension class here: Download