Building Windows Phone, Windows and Universal Apps: Winter Events Series!

*Update*: Apologies, we’ve had to cancel the Dev Workshop on Thursday 20th November.

In the late summer, we held a series of events aimed at Windows Phone and Windows 8.1 app developers intended to help you along the road to getting an app published in the Windows Store, whether you are a complete beginner or a more experienced app developer.

We are running a new series of those events this winter. We start with two one-hour webinars run back-to-back, follow those with a one day workshop at Microsoft’s offices in Victoria, London, and wrap up with a ‘Publish to the Store’ hack event again at Microsoft London:

Webinar 1: Windows Apps JumpStart LIVE Series – Kick Starter Webinar for the non C#/XAML developer: This one hour webinar is aimed at developers who are completely new to Visual Studio, XAML, C# and .NET. This will give you what they need to get started with downloading Visual Studio, a little bit of knowledge of C# and the structure of a XAML-based app.
Online webinar
Friday 7 Nov 2014  10:00 –11:00
Registration: http://aka.ms/winappswebinar1

Webinar 2: Windows Apps JumpStart LIVE Series – JumpStart Webinar: Building Universal Apps with C# and XAML: This one hour webinar follows on straight away after the previous one. It is aimed at developers who are new to Windows Store app development, but who have some experience of developing software using .NET, or for those who have attended the previous webinar.
Online webinar
Friday 7 Nov 2014    11:00 – 12:00
Registration: http://aka.ms/winappswebinar2

Following on from the webinars, we have a one-day dev camp:

Dev camp: Windows Apps JumpStart LIVE Series: Windows Apps Dev Workshop
This one day event will be help at Microsoft’s offices near Victoria Station, London, running 9:30 – 17:30. At this workshop, you will learn how to program Windows and Windows Phone apps, including universal apps that run on both. There will be Hands-on Labs available, and you can get tips and advice from Microsoft experts and from peers in the developer community. There’ll be some giveaways as well Smile
Dev camp
Sorry! This one has had to be cancelled…

And following on from that, we have a one-day Publish hackathon:

Publish event: Windows Apps JumpStart LIVE Series: Publish Hackathon
This informal one-day event will also be held at Microsoft’s building in London, running 9:00 – 21:00 on a Saturday. This is a fun 12 hour event encouraging developers to bring their existing projects (apps/cloud projects) to polish and publish through to the last mile with help from Microsoft and community experts. There’ll be pizza and drinks and prizes too!
Publish Hack event
Saturday 13 December 2014
    09:00 – 21:00
Registration: http://aka.ms/winappspublishhack

Come along and join us – and if you don’t manage to publish an app this quarter, remember we are repeating these events again the first half of next year so you can get started now and then come and join us again later!

Windows Phone 8.1 Smart card Reader sample code

I have had quite a few queries from developers who watched the Building Apps for Windows Phone 9.1 Jump Start videos and are interested in the low-level smart card reading that I showed in module 15: Sensors and Proximity: NFC and Bluetooth in which I demoed an app that read data off a bank debit card. You can find all the samples we showed in the Jump Start at http://aka.ms/wp81samples but the smartcard sample is missing from there.

There were two reasons for that: firstly, there have been no phones available that can run it! Until now that is. Low-level card reading needs a new NFC chipset that is only available in the newest phones that are only now coming to market, such as the Lumia 730 and Lumia 830. The device I used in the video was an engineering prototype. And the second reason for not publishing it was that at the time we published the code samples, I wasn’t sure we had the go-ahead from the card company whose card we used.

Anyway, now the phones are becoming available and the NFC Smart card team at Microsoft have published their ‘official’ sample up on MSDN code samples: NFC Smart Card Reader PC/SC Library . The Home page of the project explains it all perfectly, so I’ll just repeat a shortened version here:

“Example code and library for raw communication to NFC tags with Windows Phone 8.1, but requires a device with support (Lumia 830 & 73x)
NOTE: This code will work only on a Windows Phone running 8.1 or higher, and with an NFC driver that supports smart card reader mode such as the NXP PN547 which is available on the Lumia 730 and Lumia 830 (it will NOT work on a Lumia 930 or any existing hardware, even after updating to 8.1). See inside the MainPage.GetDevices() function for how to detect at runtime whether a device supports this functionality.

A new feature in Windows Phone 8.1 (on specific new hardware devices) is to be able to directly send raw commands to external plastic NFC cards, previously the phone could only read/write NDEF messages to NDEF-formatted tags but now you can talk to things like transit passes etc. For NXP PN547-based devices NFC cards such as MIFARE Classic/Ultralight/DESfire, ISO7816-4/APDU-based cards like JCOP, Jewel are supported as well as some limited support for ISO15693 and Felica. This project contains sample code only for MIFARE Classic/Ultralight/DESfire and Felica, but can be easily extended to support the others.”

So there you go! Go download this sample, get yourself one of the new phones, and start building interesting apps that interact with transit passes, security passes and take advantage of other smart card use scenarios!

Hey, Cortana – How can I integrate my app into you?

At the recent IFA 2014 show in Berlin, Microsoft announced some great new phones, the budget Lumia 730 and 735 and the ‘affordable premium’ phone the Lumia 830. Exciting new hardware – but the standout new feature for many was the announcement of ‘Hey, Cortana’, a new accessibility feature for the popular voice-controlled assistant which allows you to launch the app just by saying ‘Hey, Cortana’ at any time, avoiding the need to press the search button or the Live Tile as you do currently. This feature will be available on the high-end devices with the Snapdragon 800 processor, such as the Lumia 930, 1520 and Icon, and will be shipped as part of the Lumia ‘Denim’ firmware update coming to phones in Q4 2014. Cortana has been getting many plaudits – rightly so – and is currently available in the US, on beta in the UK and China, and will soon be rolling out as a beta soon to Australia, India and Canada, with more countries next year.

clip_image002

Speech control is part of the next wave of improvements of how we interact with our devices, part of a loose grouping of technologies often called NUI (Natural User Interface), meaning human to device interface methods that are effectively invisible, i.e. ‘natural’, as distinct from artificial ways of interacting with a device such as pressing a button which have to be learnt.

So having Cortana capable of passive listening so you can just talk to it whenever the fancy takes you and wake it up is another small step towards making speech interaction with our devices easier and more natural. It removes one more piece of friction – the need to tap on a button or tile to start the voice interaction – that could prevent users choosing voice as their favoured means of interaction with their devices rather than one only used by enthusiasts.

Integrating Apps into Cortana

So that’s great, now we can say ‘Hey, Cortana’ to invoke the built-in digital assistant features of Cortana and get it to tell us upcoming events in our calendar, set new reminders, do searches etc. But what if you want to allow users to interact with your app in a similar way, use Cortana as a conduit for speech interaction with your app? Say something like: “Hey Cortana” to invoke Cortana, and then say “MSDN find ‘Windows Phone Voice Commands’” to invoke the MSDN Voice Search app.

Well, that’s not too hard! In fact, we’ve had the technology even in Windows Phone 8.0, before Cortana was a twinkle in Halo’s eye. Back in the Windows Phone 8.0 Jump Start videos, we recorded one session all about voice commands (http://channel9.msdn.com/Series/Building-Apps-for-Windows-Phone-8-Jump-Start/Building-Apps-for-Windows-Phone-8-Jump-Start-13-Speech-Input-in-Windows-Phone-8 ) which explained how to create a Voice Command definition file to allow you to launch apps with speech. It’s that same technology that is used to launch apps through speech from Cortana.

Although it was quite easy to implement, not that many developers added voice command activation to their 8.0 apps and very few users turned to voice as their favoured method of launching their favourite app. Why not? Discoverability! To activate voice recognition on a Windows Phone 8.0 device, you had to press and hold the Windows button. Most users only ever discovered this by accident, if at all! So as a consequence, it never gained wide usage.

That’s why Cortana is so cool – everyone knows that it is the voice portal on a Windows Phone app. It’s no longer down to knowing about some unnatural user interaction mechanism – a tap and hold on the Windows key – but now you invoke Cortana by a single tap on the Search button, or by tapping on the Live Tile, or even by launching it from the Apps list. Or – better by far – by simply saying ‘Hey, Cortana’ on a top-end phone with the new Lumia Denim software. [Note that in countries that do not have Cortana yet, you can still launch apps by voice command

Voice Command Recognition in Windows Phone 8.0

The Voice Commands implementation in Windows Phone 8.0 had another limitation apart from discoverability: it was a little too inflexible. With Windows Phone 8.0 Voice Commands, the full text of the commands themselves needed to be known ahead of time—this made them difficult to use for searching, social networking, or anything else with a large vocabulary.

For example, a Windows Phone 8.0 voice command definition looks like this:

    <CommandSet xml:lang="en-gb" Name="UKenglishCommands">
        <!-- The CommandPrefix provides an alternative to your full app name for invocation -->
        <CommandPrefix> MSDN </CommandPrefix>
        <!-- The CommandSet Example appears in the global help alongside your app name -->
        <Example> search </Example>

        <Command Name="MSDNSearch">
            <!-- The Command example appears in the drill-down help page for your app -->
            <Example> do a search </Example>

            <!-- ListenFor elements provide ways to say the command, including references to 
            {PhraseLists} and {PhraseTopics} as well as [optional] words -->
            <ListenFor> [do a] Search [for] {*} </ListenFor>
            <ListenFor> Find {*} </ListenFor>
            <ListenFor> Look [for] {*} </ListenFor>

            <!--Feedback provides the displayed and spoken text when your command is triggered -->
            <Feedback> Searching MSDN... </Feedback>

            <!-- Navigate specifies the desired page or invocation destination for the Command-->
            <Navigate Target="MainPage.xaml" />
        </Command>
    </CommandSet>

Every command must start with the CommandPrefix – ‘MSDN’ in this case. Thereafter, the ListenFor elements define the different variants for a specific speech command, and these may include optional words if they are enclosed in square brackets. There is the ability to allow for free speech, which is represented by {*} but that still had to be preceded by some fixed speech components in the command. So for this example, all of the following will trigger the voice command:

  • Search xyz
  • Search for xyz
  • Find xyz
  • Look xyz
  • Look for xyz

But the following will *not* be recognised because it doesn’t fit into one of the ListenFor definitions:

  • I want to know about xyz

Recognizing natural language in Windows Phone 8.1

The Voice Command Definition for 8.1 allows more flexibility:

<?xml version="1.0" encoding="utf-8"?>

<!-- Be sure to use the new v1.1 namespace to utilize the new PhraseTopic feature -->
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.1">
    <!-- The CommandSet Name is used to programmatically access the CommandSet -->
    <CommandSet xml:lang="en-gb" Name="UKenglishCommands">
        <!-- The CommandPrefix provides an alternative to your full app name for invocation -->
        <CommandPrefix>MSDN</CommandPrefix>
        <!-- The CommandSet Example appears in the global help alongside your app name -->
        <Example> find 'Windows Phone Voice Commands' </Example>

        <Command Name="MSDNSearch">
            <!-- The Command example appears in the drill-down help page for your app -->
            <Example> find 'how to install CommandSets' </Example>

            <!-- ListenFor elements provide ways to say the command, including references to 
            {PhraseLists} and {PhraseTopics} as well as [optional] words -->
            <ListenFor> Search </ListenFor>
            <ListenFor> Search [for] {dictatedSearchTerms} </ListenFor>
            <ListenFor> Find {dictatedSearchTerms} </ListenFor>
            <ListenFor> Find </ListenFor>

          <!--Feedback provides the displayed and spoken text when your command is triggered -->
            <Feedback> Searching MSDN... </Feedback>

            <!-- Navigate specifies the desired page or invocation destination for the Command-->
            <Navigate Target="MainPage.xaml" />
        </Command>

        <Command Name="MSDNNaturalLanguage">
            <Example> I want to go to the Windows Phone Dev center </Example>
            <ListenFor> {naturalLanguage} </ListenFor>
            <Feedback> Starting MSDN... </Feedback>
            <Navigate Target="MainPage.xaml" />
        </Command>

        <PhraseTopic Label="dictatedSearchTerms" Scenario="Search">
            <Subject> MSDN </Subject>
        </PhraseTopic>

        <PhraseTopic Label="naturalLanguage" Scenario="Natural Language">
            <Subject> MSDN </Subject>
        </PhraseTopic>

    </CommandSet>
</VoiceCommands>

Notice the following ListenFor elements:

        <Command Name="MSDNSearch">
           …
            <ListenFor> Search [for] {dictatedSearchTerms} </ListenFor>
           …
        </Command>
        <Command Name="MSDNNaturalLanguage">
            …
            <ListenFor> {naturalLanguage} </ListenFor>
            …
        </Command>

Both of these elements contain a label inside curly brackets which refers to the PhraseTopic elements defined towards the bottom. First dictatedSearchTerms is defined as:

        <PhraseTopic Label="dictatedSearchTerms" Scenario="Search">
            <Subject> MSDN </Subject>
        </PhraseTopic>

A PhraseTopic is a new element in 8.1 which specifies a topic for large vocabulary definition. What this means is that the voice input goes up to the cloud where it is recognized against the same large vocabulary of words that Cortana uses for its built-in functions. The Scenario attribute is used to guide the recognition. Valid values are “Natural Language”, “Search”, “Short Message”, “Dictation” (the default), “Commands”, and “Form Filling”. The Subject child element specifies a subject specific to the parent PhraseTopic’s Scenario attribute to further refine the relevance of speech recognition results.

So the command that uses this ListenFor definition allows free speech searches in MSDN.

The second ListenFor element has no fixed command terms at all:

<ListenFor> {naturalLanguage} </ListenFor>

Where naturalLanguage is defined as:

        <PhraseTopic Label="naturalLanguage" Scenario="Natural Language">
            <Subject> MSDN </Subject>
        </PhraseTopic>

Effectively, this defines an ‘anything goes’ command, so this can recognize a query such as “I want to know about xyz”. Consider this a free-form alternative to the other, more rigid, command labelled MSDNSearch where the ListenFor elements define fixed components of the speech command (‘Find’, ‘Search’) that must be present for recognition to succeed.

But how then does the app know what it should do when “Natural Language” speech input is recognized? There’s no magic here, you have to code your app to search for elements in the recognized speech that have relevance to that apps problem domain. The MSDN Voice Search sample app (link in the ‘Further Reading’ section at the end) is coded to recognise variants on ‘Take me to the Windows Dev Center’ and if that isn’t found falls back to a default of a search on Bing for whatever speech input was recognized. We’ll look at how this is done in just a moment.

Handing Speech Commands in your app

I’m not going to go into all the coding techniques used to handle voice activation here. Watch the BUILD video (link below in ‘Further Reading’) for an excellent overview of handling voice activation in both Silverlight and Windows Runtime apps, and download the sample app (link also below). But I will just call out how to handle Natural Language input.

The sample app contains the following code for handling this:

        /// <summary>
        /// Given a query string from the user, attempts rudimentary "natural language" string processing in an
        /// effort to derive a specific, curated action from the text; if a match is found, that curated action
        /// is taken. If not, the string is unhandled and should be handled elsewhere.
        /// </summary>
        /// <param name="query"> the query to attempt processing and action upon </param>
        /// <param name="actSilently"> whether or not to only take actions without audio feedback </param>
        /// <returns></returns>
        private bool TryHandleNlQuery(string query, bool actSilently)
        {
            // There are a variety of ways to say things like "I want to go to Windows Phone Dev Center"; let's load
            // some alternatives for the key components of this.
            string[] intentMarkers = AppResources.NaturalLanguageCommandIntentMarkers.Split(new char[] { ';' });
            string[] wpDevCenterNames = AppResources.WPDevCenterNames.Split(new char[] { ';' });

            int intentIndex = -1;
            int destinationIndex = -1;

            Uri destinationUri = null;
            string confirmationTts = null;

            // First we'll try to find a match for the "intent marker," e.g. "go to"
            foreach (string marker in intentMarkers)
            {
                intentIndex = query.IndexOf(marker, StringComparison.InvariantCultureIgnoreCase);
                if (intentIndex >= 0)
                {
                    break;
                }
            }

            if (intentIndex >= 0)
            {
                // Now we'll try to figure out a destination--if it comes after the intent marker in the string, we'll
                // store the destination and spoken feedback.
                foreach (string wpDevCenterName in wpDevCenterNames)
                {
                    destinationIndex = query.IndexOf(wpDevCenterName, StringComparison.InvariantCultureIgnoreCase);
                    if (destinationIndex > intentIndex)
                    {
                        destinationUri = new Uri(AppResources.WPDevCenterURL);
                        confirmationTts = AppResources.SpokenWPDevCenterSsml;
                        break;
                    }
                }
            }

            // If we found a destination to go to, we'll go there and--if allowed--provide the corresponding spoken
            // feedback.
            if (destinationUri != null)
            {
                if (!actSilently && (confirmationTts != null))
                {
                    StartSpeakingSsml(confirmationTts);
                }

                StartBrowserNavigation(destinationUri);
            }

            // If we found a destination, we handled the query. Otherwise, it hasn't been handled yet.
            return (destinationUri == null); ;
        }

That’s a lot of code, and essentially all it does is look for a number of different variants on ‘I want to go to the Windows Dev Center’. Key to understanding it is knowing that in the Resources file, the command intents and variations for the dev center name are defined:

NaturalLanguageCommandIntentMarkers: show me;go to;take me to;bring up;navigate to;launch
WPDevCenterNames: Phone Dev Center;Phone Developer Center

So all the code shown above actually does is to search for a match on the recognized text for one of the NaturalLanguageCommandIntentMarkers, followed by one of the options for WPDevCenterNames. If it matches then the app takes you to the Windows dev center. If you follow through on the sample code, you’ll see that if no match is found, then the default fallback action is just to invoke a Bing search for the recognized text.

Like I said – there’s no magic here. You just have to write code to analyse the recognized speech for strings that make sense for that app, and this could be quite a lot of code!

Parting thoughts…

Before I close, three further thoughts on Speech enabling your apps:

First, make sure you include Command definitions in your vcd file for all languages you want to support. The sample app has commands defined only for US English:

    <!-- The CommandSet Name is used to programmatically access the CommandSet -->
    <CommandSet xml:lang="en-us" Name="englishCommands">

which means that when you run it on a UK English or Australian English device, the voice commands don’t work! You have to define for each individual language you want, which could get a bit tedious. But be warned – it caught me out!

Secondly, make sure you detect when the user has typed into Cortana rather than used speech. If they typed in, don’t go speaking back to them – they typed quite possibly because they were in a meeting, so it would not be helpful to start speaking out sports results or whatever! The sample app and the BUILD video show you how to do this.

And thirdly, your user has to run the app at least once to run the code to register the speech commands with the system. Unfortunately, speech commands do not get activated just by installing the app. So the first time the user runs the app, that might be a good time to pop up a ‘Did you know?’ screen to tell them about the speech commands your app supports. All helps towards the users’ discoverability of these kind of features.

Further reading

· Video: Integrating Your App into the Windows Phone Speech Experience http://channel9.msdn.com/Events/Build/2014/2-530

· Sample: MSDN Voice Search for Windows Phone 8.1 http://code.msdn.microsoft.com/MSDN-Voice-Search-for-95c16d92

· Speech team blog post: Integrating Store Apps with Cortana in Windows Phone 8.1 http://blogs.bing.com/search/2014/04/14/integrating-store-apps-with-cortana-in-windows-phone-8-1/

Voice command element and attribute reference (Windows Phone Store apps using C#/VB/C++ and XAML)
http://msdn.microsoft.com/en-us/library/dn630431.aspx

Windows Apps JumpStart Publish Hack

Don’t forget, if you can get to London on Saturday September 20th, come to our Publish Hack at Microsoft’s Cardinal Place offices near Victoria Station and get your app published to store! Our goal for this day is to make it a fun, informal day where you can overcome those last blockers and issues that are preventing you getting over those last yards to publication. There will be fun, and pizza, and beer….oh, yes – and prizes!

We will have experts from Microsoft and from the developer community there to help you, including elite Windows App engineers from our App Consult program.

Did I mention prizes? Yes, as if the fun of taking part wasn’t enough, we’re going to give you additional incentive to take part by offering prizes, including:

- Nokia Lumia 1020 phones

- Nokia Lumia 1520 phablets

- Nokia Contactless Charging units

- Arc Mice

- Arc Keyboards

- A Goodie bag for every single developer that publishes an app on the day!

The prizes will be awarded for quality, progress made and for good old-fashioned sweat and tears.

Details and registration page:

Windows Apps JumpStart Publish Hack
Saturday 20 Sep – 9AM – 9PM
http://aka.ms/winappspublishhack 

Hope you can come along!

Windows Apps JumpStart LIVE Events Series

We’re starting a new series of events for UK developers that will help you on the journey from initial interest in developing apps for Windows 8 and Windows Phone right the way through to publishing an app to the Windows Store. You can join into the series at whichever point makes sense to you, so whether you’ve never opened Visual Studio before or written a line of C#, or you’re a developer who has already written software using out tools and languages but are new to apps, we can help you get to that point where you’re publishing your first app into our store. And we’re going to repeat the series of events every quarter, so you can jump on and off the series and attend events at whatever pace makes sense to you.

We start with two one-hour webinars run back-to-back:

Webinar 1: Windows Apps JumpStart LIVE Series – Kick Starter Webinar for the non C#/XAML developer: This one hour webinar is aimed at developers who are completely new to Visual Studio, XAML, C# and .NET. This will give you what they need to get started with downloading Visual Studio, a little bit of knowledge of C# and the structure of a XAML-based app.

Webinar 2: Windows Apps JumpStart LIVE Series – JumpStart Webinar: Building Apps with C# and XAML: This one hour webinar follows on straight away after the previous one. It is aimed at developers who are new to Windows Store app development, but who have some experience of developing software using .NET, or for those who have attended the previous webinar.

Following on from the webinars, we have a one-day dev camp:

Dev camp: Windows Apps JumpStart LIVE Series: Windows Apps Dev Workshop
This one day event will be help at Microsoft’s offices near Victoria Station, London, running 9:30 – 18:00. At this workshop, you will learn how to program Windows and Windows Phone apps, including universal apps that run on both. There will be Hands-on Labs available, and you can get tips and advice from Microsoft experts and from peers in the developer community.

And following on from that, we have a one-day Publish hackathon:

Publish event: Windows Apps JumpStart LIVE Series: Publish Hackathon
This informal one-day event will also be held at Microsoft’s building in London, running 9:00 – 21:00 on a Saturday. This is a fun 12 hour event encouraging developers to bring their existing projects (apps/cloud projects) to polish and publish through to the last mile with help from Microsoft and community experts.

First events are coming up fast!:

Come along and join us – and if not this quarter, remember we are repeating these events throughout the year so you can join us when you can!

Windows Apps JumpStart LIVE Events Series

We’re starting a new series of events for UK developers that will help you on the journey from initial interest in developing apps for Windows 8 and Windows Phone right the way through to publishing an app to the Windows Store. You can join into the series at whichever point makes sense to you, so whether you’ve never opened Visual Studio before or written a line of C#, or you’re a developer who has already written software using out tools and languages but are new to apps, we can help you get to that point where you’re publishing your first app into our store. And we’re going to repeat the series of events every quarter, so you can jump on and off the series and attend events at whatever pace makes sense to you.

We start with two one-hour webinars run back-to-back:

Webinar 1: Windows Apps JumpStart LIVE Series – Kick Starter Webinar for the non C#/XAML developer: This one hour webinar is aimed at developers who are completely new to Visual Studio, XAML, C# and .NET. This will give you what they need to get started with downloading Visual Studio, a little bit of knowledge of C# and the structure of a XAML-based app.

Webinar 2: Windows Apps JumpStart LIVE Series – JumpStart Webinar: Building Apps with C# and XAML: This one hour webinar follows on straight away after the previous one. It is aimed at developers who are new to Windows Store app development, but who have some experience of developing software using .NET, or for those who have attended the previous webinar.

Following on from the webinars, we have a one-day dev camp:

Dev camp: Windows Apps JumpStart LIVE Series: Windows Apps Dev Workshop
This one day event will be help at Microsoft’s offices near Victoria Station, London, running 9:30 – 18:00. At this workshop, you will learn how to program Windows and Windows Phone apps, including universal apps that run on both. There will be Hands-on Labs available, and you can get tips and advice from Microsoft experts and from peers in the developer community.

And following on from that, we have a one-day Publish hackathon:

Publish event: Windows Apps JumpStart LIVE Series: Publish Hackathon
This informal one-day event will also be held at Microsoft’s building in London, running 9:00 – 21:00 on a Saturday. This is a fun 12 hour event encouraging developers to bring their existing projects (apps/cloud projects) to polish and publish through to the last mile with help from Microsoft and community experts.

First events are coming up fast!:

Come along and join us – and if not this quarter, remember we are repeating these events throughout the year so you can join us when you can!

Windows Phone 8.1 Jump Start is coming!

I’m pleased to announce that the registration page is now up for this year’s Windows Phone Jump Start!

Building Apps for Windows Phone 8.1 Jump Start will be held on 29th, 30th April and extend onto the morning of May 1st. As it says on the website: “If you’re an app developer who wants to design and build Windows Phone 8.1 apps using XAML and C#, don’t miss this exciting event. The two-and-a-half day, demo-rich course, taught by experts who have years of experience developing (and writing about the process), focuses on how to create apps for Windows Phone 8.1 in Visual Studio and how to create universal app projects that share a high percentage of code and that target both Windows and Windows Phone.”

This time around, the Jump Start is structured into 4 main parts:

Section 1: Introduction

· Session 1: Introduction to Windows Phone 8.1 (50 minutes)
Overview of the Windows Phone 8.1 developer platform, including guidance on the choices of app framework now available.

Section 2: Building Windows Runtime Apps using XAML and C#

Sessions that show how to build phone apps using WinRT XAML

· Session 2: Getting Started Building Windows Runtime Apps (50 minutes)
Fundamentals of building a WinRT XAML app for a Phone target, introducing the controls, layout, styles and theme resources, AppBar, StatusBar.

· Session 3: Page Navigation and Data Binding (25 minutes)
Navigating between pages in a Windows Runtime app, page caching and data binding

· Session 4: Lists and List Items (50 minutes)
Programming Lists, formatting list items and handling long or complex lists effectively

· Session 5: Windows Runtime App Page Layout Controls (25 minutes)
Pivot, Hub and Single Page layouts.

· Session 6: Adapting UI for Different Screens (25 minutes)
Explain the new layout system, and how to ensure your UI adapts to different phone screen sizes and orientations.

· Session 7: Windows Runtime App Lifecycle (25 minutes)
Explain the ways apps can be started, terminated and resumed.

· Session 8: Localization and Globalization in Windows Runtime Apps (25 minutes)
Making your app world-ready

Section 3: Programming Windows Runtime Platform Features (Windows Runtime XAML and Silverlight 8.1)

Programming platform features in Windows Phone 8.1 apps from either Windows Runtime Apps or Windows Phone Silverlight Apps 

· Session 9: Data Storage, Backup and Roaming (50 minutes)
All about storing data, backing app data up to the cloud and roaming data across devices

· Session 10: Contracts and Sharing Files and Data (50 minutes)
Share contract, FileOpenPicker/FileSavePicker, File & Uri associations

[Day 2]

· Session 11: Background Tasks (25 minutes)
How to run code in the background

· Session 12: Maps, Geolocation and Geofencing (25 minutes)
Maps, Location and GeoFencing

· Session 13: Networking, Mobile Services and Authentication (50 minutes)
Networking fundamentals. Includes Background Transfer Service and Web Authentication Broker 

· Session 14: Tiles, badges and toasts and Notification Center (50 minutes)
Tiles and toasts and Notification Center

· Session 15: Sensors and Proximity: NFC and Bluetooth (25 minutes)
Sensors, NFC and Bluetooth

· Session 16: Contacts and Calendar (25 minutes)
WinRT APIs for Contacts and Calendar, plus new capabilities (available on phone only) for Wallet-aware apps

· Session 17: Camera, Media, Audio and Speech (50 minutes)
Working with the camera, media and video editing

· Session 18: Enterprise LOB Apps (50 minutes)
All the new features aimed at Enterprise LOB and MDDM

· Session 19: SQLite Database (25 minutes)
How to program SQLite

· Session 20: VS Tooling and Memory Profiling (25 minutes)
Introduction to the many tools built into Visual Studio to help you develop Windows apps

[Day 3]

· Session 21: App Packaging and Publication (50 minutes)
How to package your app and get your app published in the Store

· Session 22: Best practices: Building Universal Apps for Windows Phone and Windows (50 minutes)
Guidance for building for both

Section 4: Upgrading Windows Phone Silverlight 8.0 apps to Silverlight 8.1

Programming new platform features from a Silverlight app

· Session 23: Upgrading Windows Phone Silverlight 8.0 Apps to Silverlight 8.1 (50 minutes)
Recap on why you would use Silverlight, and explanation of what issues must be considered when upgrading to Silverlight 8.1. Topics include behavioural changes introduced by the quirks API, Lifecycle changes as FAR is now the only mode of reactivation, implementing share contract and using the FileOpenPicker/FileSavePicker, Web Authentication Broker, moving from MPNS to WNS, background agents alongside background tasks.

Hope you can join us for the live event.  The event is happening in Redmond and will be from 9:00am – 5:00pm Pacific Daylight Time. We realize that doesn’t make it the most convenient timeslots for everyone, but if you can’t watch it all, we hope you will join us when you can, and then catch up with the full list of sessions when the videos are posted on Channel9 shortly after!

Registration page can be found here!

SQLiteWinRT: Opening databases shipped as app content or from an SD Card

Recently, I was asked about opening a database file inserted into a device on an SD card. I had to make a slight change to the SQLWinRT wrapper to enable it, so this post explains how, and also looks at opening databases shipped in the app package as content.

Opening databases shipped as content

You can include a prepopulated SQLite database in your Windows 8.x or Windows Phone app package. When the user installs the app, the database file ends up in the App Install folder where you can open it from your code – but only in a read-only fashion:

public static async void LoadDatabase()
{
    // Get a reference to the SQLite database
    db = new SQLiteWinRT.Database(
        Windows.ApplicationModel.Package.Current.InstalledLocation, 
        "customers.sqlite");

    await db.OpenAsync(SQLiteWinRT.SqliteOpenMode.OpenRead);

    // PRAGMA temp_files=2 causes temporary files to be created in memory
    // rather than in a physicalfile in the same folder as the database
    // Note that temp files only really get used if you are going to do 
    // complicated JOINs etc
    await db.ExecuteStatementAsync("PRAGMA temp_files=2");
}

If you want to have read-write access to the database, you must copy it from the install folder to the local folder first.

async Task CopyDatabaseAsync()
{
    // Has the database been copied already?
    try
    {
        await ApplicationData.Current.LocalFolder.GetFileAsync("customers.sqlite");
        // No exception? It exists...
        return;
    }
    catch (System.IO.FileNotFoundException)
    {   // Expected response - no-op 
    }

    StorageFile dbfile = await StorageFile.GetFileFromApplicationUriAsync(
        new Uri("ms-appx:///customers.sqlite"));
    await dbfile.CopyAsync(ApplicationData.Current.LocalFolder);
}

Opening a Database on an SD Card

A database file that you open from an SD Card is related to the previous case in that it is read-only. You cannot write to any file on an SD Card from any app in Windows Phone 8.

I haven’t researched it thoroughly, but you should be able to open a database file on removable storage in a Windows 8.x Store app. You will have to request the Removable Storage capability in the app manifest, and declare the file extensions you want to access in the app manifest as well. Then you should be able to get a StorageFile reference to the database file using techniques similar to those discussed here: http://lunarfrog.com/blog/2012/10/27/external-storage-devices/   . When I’ve tried it, I’ll update this post!

What I have tried though, is doing this on a Windows Phone 8 device that has an SD card slot, such as the Nokia Lumia 820. As with Windows 8, you have to declare the file extensions you want to access in the manifest. For example, add the following after the closing </Tokens> tag:

    <Extensions>
      <FileTypeAssociation Name="sqlite" TaskID="_default" NavUriFragment="fileToken=%s">
        <SupportedFileTypes>
          <FileType ContentType="application/sqlite">.sqlite</FileType>
        </SupportedFileTypes>
      </FileTypeAssociation>
    </Extensions>

Then in your code, you can open a read-only connection to the database as follows:

public static async void LoadDatabase()
{
    // Get a reference to the SQLite database
    ExternalStorageDevice _sdCard = 
        (await ExternalStorage.GetExternalStorageDevicesAsync())
        .FirstOrDefault();

    if (_sdCard == null)
    {
        MessageBox.Show("No SD Cards found");
        return;
    }
    else
    {
        ExternalStorageFile dbStoragefile = 
            await _sdCard.GetFileAsync("customers.sqlite");
        db = new SQLiteWinRT.Database(dbStoragefile.Path);
    }

    await db.OpenAsync(SQLiteWinRT.SqliteOpenMode.OpenRead);

    // PRAGMA temp_files=2 causes temporary files to be created in memory
    // rather than in a physicalfile in the same folder as the database 
    // Note that temp files only really get used if you are going to do 
    // complicated JOINs etc
    await db.ExecuteStatementAsync("PRAGMA temp_files=2");
}

Important: I had to modify the wrapper code posted up on http://sqlwinrt.codeplex.com in order to enable this usage. I added a new override of the Database object constructor that just takes the path to the database file as a string. Earlier versions had one override of the constructor that took a Windows.Storage.StorageFile parameter and another that took a Windows.Storage.StorageFolder and the filename as string, but neither of those were usable since the ExternalStorageFile object is not as you might expect a derivative of Windows.Storage.StorageFile, but is instead in the Microsoft.Phone.Storage namespace – hence I had to create a new constructor.

Download the latest version of the wrapper code from http://sqlwinrt.codeplex.com to get this update – note that this is built against SQLite version 3.8.2 – make sure you update to this version using the Visual Studio – Tools – Extensions and Updates wizard.

Download the sample project here

Note that it covers both scenarios covered in this post. At the top of app.xaml.cs there is a compile time symbol #define USE_SDCARD – comment this out to test the ‘database shipped as content’, or leave it in to test the SD card access. You’ll need a real device for the latter and before testing the app use your PC to copy the customers.sqlite file from the project onto the sd card and insert into your phone. Sadly, the emulator does not emulate a removable storage card!

NDC London 2013

I just spent 3 enjoyable days at the NDC conference in London. NDC usually stands for Norwegian Developer Conference which happens every June in Oslo, Norway and which is a popular conference – I really hope that I can speak there next June! The organisers of that, NDC Conferences, decided to bring their show to London – hence this weeks’ show – with NDC modified slightly to stand for ‘New Developer’s Conference’

And what a show! – great speakers, great food, large, comfortable venue, loads of sessions and an awesome party. Congratulations to NDC for putting on a great event, and I look forward to supporting them in future years.

My own contribution was two sessions: Windows Phone Networking Toolkit which was an update of a session I gave at TechEd this year, and which works through various topics related to effective network programming on Windows Phone, and Creating Killer Windows Phone Apps, a brand new session looking at ways to improve the quality of your apps. That went well and I look forward to repeating it somewhere soon. It looks at correct use of the animations in the Windows Phone Toolkit, programming Push Notifications using Windows Azure Notifications Hubs, localizing your app with the Multilingual Toolkit and reducing your memory footprint to improve your apps performance on low memory devices.

The slides for the sessions are available here:

How to massively improve SQLite Performance (using SqlWinRT)

Use ConfigureAwait(false) on calls to SqlWinRT async methods to improve INSERT performance up to 145 times, and SELECT performance up to 80 times 

Sample project: SQLitePerformance.zip

I have been seeing a few comments by people complaining of poor performance when executing SELECT statements against a SQLite database using the SQLWinRT wrapper, or when adding new records using multiple consecutive INSERT statements.

With many relational databases, poor performance on INSERT can often be rectified just by wrapping all your operations within a single transaction. If you don’t explicitly declare a transaction when programming against SQLite, the database engine creates an implicit transaction for each statement execution and that has an overhead associated with it, so by wrapping all your INSERTs inside a single transaction, you would expect a performance boost.

With SELECT operations, poor performance is often just down to not having the correct keys defined. If you have a statement such as SELECT * FROM CUSTOMER WHERE NAME = ‘CONTOSO’ and you execute it on a database where you have not defined a key on the NAME column, the only way the database engine can find the required record is to start at the first record and read sequentially down the table until it reaches the end in order to select the rows to return (called a ‘Table Scan’). If you simply want to select all the records in a table (SELECT * FROM CUSTOMER), then you can’t avoid the Table Scan – in fact that’s what you want – so you would expect that there wasn’t very much you could do to improve performance in that case.

Well – that’s the theory. I set about building a simple demo to demonstrate these points, but it didn’t turn out quite how I expected! It turns out that, important though the points already mentioned are, the most important factor BY FAR is how you call the async methods of the SQLWinRT API! Read on…

The Test Program

For my test program, I was inspired by this post on Stack Overflow: How do I improve the performance of SQLite. That post is quite old and is talking about C++ dev, so not directly relevant to Windows Phone or Windows Store app development using managed code, but I liked the test case, which was to take a large dataset from the City of Toronto’s publically available transportation data. Unfortunately, the exact same dataset used in the original post isn’t available anymore, so I couldn’t do a direct comparison, but they did have the Transportation Trips dataset, containing 128982 records that we can first insert into a SQLite database, and then select them out again.

SQLite Bulk Insert

The dataset is in the form of a CSV text file, representing 128982 rows, each containing 8 columns. The code to read the file and extract the values  looks like this:

SQLiteWinRT.Database db;

private async void Button_Start_Click(object sender, RoutedEventArgs e)
{
    int Route_ID;
    int Service_ID;
    int Trip_ID;
    string Trip_Headsign;
    int Direction_ID;
    int Block_ID;
    int Shape_ID;
    bool Wheelchair_Accessible;

    Button_Start.IsEnabled = false;

    /*********************************************/
    /* Open the Database and create the Schema */
    await LoadDatabase();

    Stopwatch sw = Stopwatch.StartNew();
    int n = 0;

    // Prepare statement
    using (var statement = await db.PrepareStatementAsync(
        @"INSERT INTO TTC (id, Route_ID, Service_ID, Trip_ID, 
                           Trip_Headsign, Direction_ID, Block_ID, 
                           Shape_ID, Wheelchair_Accessible) 
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"))
    {
        // Start transaction
        await db.ExecuteStatementAsync("BEGIN TRANSACTION");

        /*********************************************/
        /* Open input file and import into Database*/
        var inputfile = await Windows.ApplicationModel.Package.Current.
            InstalledLocation.GetFileAsync("trips.txt");
        using (var inputStream = await inputfile.OpenSequentialReadAsync())
        {
            using (StreamReader rdr = 
                new StreamReader(inputStream.AsStreamForRead()))
            {
                while (true)
                {
                    string inputline = await rdr.ReadLineAsync();
                    if (inputline == null)
                        break;

                    // Discard line 0 - header line
                    if (n > 0)
                    {
                        string[] fields = inputline.Split(new char[] { ',' });

                        Route_ID = Int32.Parse(fields[0]); ;
                        Service_ID = Int32.Parse(fields[1]);
                        Trip_ID = Int32.Parse(fields[2]);
                        Trip_Headsign = fields[3];
                        Direction_ID = Int32.Parse(fields[4]);
                        Block_ID = Int32.Parse(fields[5]);
                        Shape_ID = Int32.Parse(fields[6]);
                        Wheelchair_Accessible = fields[7] == "1" ? true : false;

                        /* Bind parameter values and Insert */
                        statement.Reset();
                        statement.BindIntParameterAt(1, n);
                        statement.BindIntParameterAt(2, Route_ID);
                        statement.BindIntParameterAt(3, Service_ID);
                        statement.BindIntParameterAt(4, Trip_ID);
                        statement.BindTextParameterAt(5, Trip_Headsign);
                        statement.BindIntParameterAt(6, Direction_ID);
                        statement.BindIntParameterAt(7, Block_ID);
                        statement.BindIntParameterAt(8, Shape_ID);
                        statement.BindIntParameterAt(9, Wheelchair_Accessible ? 1 : 0);

                        await statement.StepAsync();
                    }

                    n++;

                    if (n % 100 == 0)
                    {
                        progressBar.Value = n;
                    }
                }
            }
        }

        // Commit transaction
        await db.ExecuteStatementAsync("COMMIT TRANSACTION");
    }

    db.Dispose();
    db = null;

    var report = String.Format(
        "Inserted {0:d} records in {1:0.00} seconds", 
        n - 1, 
        (double)sw.ElapsedMilliseconds / 1000);
    MessageBox.Show(report);

    Button_Start.IsEnabled = true;
}

private async Task LoadDatabase()
{
    db = new SQLiteWinRT.Database(
        ApplicationData.Current.LocalFolder, "sqliteperf.db");

    await db.OpenAsync();

    string sql = @"
        CREATE TABLE IF NOT EXISTS TTC 
            (id INTEGER PRIMARY KEY, 
                Route_ID INTEGER, 
                Service_ID INTEGER, 
                Trip_ID INTEGER, 
                Trip_Headsign TEXT,
                Direction_ID INTEGER, 
                Block_ID INTEGER, 
                Shape_ID INTEGER, 
                Wheelchair_Accessible BOOL)";

    await db.ExecuteStatementAsync(sql);
}

Using this code, and by commenting out lines here and there as appropriate, we can test three scenarios:

  • Processing the input file but not inserting records in the database (this just gives us the time for the file processing)
  • Uncomment the call to StepAsync() to Insert each record into the database individually
  • Uncomment the lines executing the BEGIN TRANSACTION, END TRANSACTION statements so all records are inserted inside a single transaction

testrunner  Transaction

And the results? Well, not great, to be honest:

Test Total Time (seconds) – 128982 records Insert Time per record (ms)
Process records – no insert 7 -
Insert records individually 6307 49
Insert records within a containing transaction 3177 25

Although wrapping all the inserts into a single transaction halves the time it takes to insert the 128982 records compared to separate operations (where the database engine will activate an implicit transaction for every insert), we are still only getting 25ms per insert, or 40 operations per second. That’s not too impressive.

Trying ConfigureAwait(false)

Those performance figures are disappointing and make bulk insert operations in a Windows Phone or Windows Store app impractical. However, look what happens when we make a subtle change to the main loop of code:

Stopwatch sw = Stopwatch.StartNew();
int n = 0;

// Prepare statement
using (var statement = await db.PrepareStatementAsync(
    @"INSERT INTO TTC (id, Route_ID, Service_ID, Trip_ID, Trip_Headsign, 
                        Direction_ID, Block_ID, Shape_ID, Wheelchair_Accessible) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"))
{
    // Start transaction
    await db.ExecuteStatementAsync("BEGIN TRANSACTION");

    /*********************************************/
    /* Open input file and import into Database*/
    var inputfile = await Windows.ApplicationModel.Package.Current.
        InstalledLocation.GetFileAsync("trips.txt");
    using (var inputStream = await inputfile.OpenSequentialReadAsync())
    {
        using (StreamReader rdr = new StreamReader(inputStream.AsStreamForRead()))
        {
            while (true)
            {
                string inputline = await rdr.ReadLineAsync();
                if (inputline == null)
                    break;

                // Discard line 0 - header line
                if (n > 0)
                {
                    string[] fields = inputline.Split(new char[] { ',' });

                    Route_ID = Int32.Parse(fields[0]); ;
                    Service_ID = Int32.Parse(fields[1]);
                    Trip_ID = Int32.Parse(fields[2]);
                    Trip_Headsign = fields[3];
                    Direction_ID = Int32.Parse(fields[4]);
                    Block_ID = Int32.Parse(fields[5]);
                    Shape_ID = Int32.Parse(fields[6]);
                    Wheelchair_Accessible = fields[7] == "1" ? true : false;

                    /* Bind parameter values and Insert */
                    statement.Reset();
                    statement.BindIntParameterAt(1, n);
                    statement.BindIntParameterAt(2, Route_ID);
                    statement.BindIntParameterAt(3, Service_ID);
                    statement.BindIntParameterAt(4, Trip_ID);
                    statement.BindTextParameterAt(5, Trip_Headsign);
                    statement.BindIntParameterAt(6, Direction_ID);
                    statement.BindIntParameterAt(7, Block_ID);
                    statement.BindIntParameterAt(8, Shape_ID);
                    statement.BindIntParameterAt(9, Wheelchair_Accessible ? 1 : 0);

                    await statement.StepAsync().AsTask().ConfigureAwait(false);
                }

                n++;
                if (n % 100 == 0)
                {
                    Dispatcher.BeginInvoke(()=>progressBar.Value = n);
                }
            }
        }
    }

    // Commit transaction
    await db.ExecuteStatementAsync("COMMIT TRANSACTION");
}

db.Dispose();
db = null;

Dispatcher.BeginInvoke(() =>
    {
        var report = String.Format(
            "Inserted {0:d} records in {1:0.00} seconds", 
            n - 1, (double)sw.ElapsedMilliseconds / 1000);
        MessageBox.Show(report);

        Button_Start.IsEnabled = true;
    });
}

The main – and significant change above – is that the StepAsync() method is now called in a different way:

await statement.StepAsync().AsTask().ConfigureAwait(false);

In addition, the code that ‘touches’ the UI, such as the MessageBox.Show() call, and the code setting the ProgressBar is now called using Dispatcher.BeginInvoke(Action a). This is necessary because the change to how StepAsync() is called has a knock-on effect of causing the code to end up executing on a background thread – I will explain more on this shortly.

What does this do to the timings?:

Test Total Time (seconds) – 128982 records Insert Time per record (ms)
Process records – no insert 7 -
Insert records individually 6307 49
Insert records within a containing transaction 3206 25
Insert individually with ConfigureAwait(false) 2791 21
Insert within a transaction with ConfigureAwait(false) 55 0.43

TransactionWithConfigureAwait

WHOA! What happened there? If you insert records within a transaction and use ConfigureAwait(false), you can achieve insert performance of one insert every 0.43 ms, or 2345 records per second. Now we’re talking! That means the performance of inserting records individually without using ConfigureAwait(false) is more than 144 times slower than the best case.

Why such a dramatic improvement? Well, the Task.ConfigureAwait(bool continueOnCapturedContext) method is used to configure the awaiter used to await the result of the asynchronous operation. An awaiter is an object you don’t see or program directly as a developer, but simply by using the await keyword when calling an asynchronous method, the compiler will generate code that uses an awaiter to handle the suspension and reactivation of your calling method while it waits for some asynchronous operation to complete. When the asynchronous method has completed, the awaiter resumes execution of your code which by default happens on the same context (think ‘thread’) you were on when you called the async method. But if you set ConfigureAwait(false), it doesn’t do that but instead continues on whatever context the async method executed on. There’s a performance advantage to this, which is why the advice to authors of library code is that you should always make async calls within your library code using ConfigureAwait(false) – the caller of your library method can then make the decision on whether to return to their original context by choosing whether or not to use ConfigureAwait(false) on the call to your async library method.

Which is what we are doing here – by setting ConfigureAwait(false) on our call to SqlWinRT:Statement.StepAsync() we are saying “don’t bother continue on the originating context, stay on whatever context you are executing on”. And as you can see, the performance gain is spectacular! To be honest, I was very surprised just how spectacular the performance improvement is. Normally, you would expect a modest performance gain, but I guess that because this call is happening between managed code and a WinRT component, the overhead of ConfigureAwait(true) - the default – is particularly significant.

One consequence of using ConfigureAwait(false) is that our code after the await call resumes on a background thread, so when we want to interact with the UI, such as to set the ProgressBar or to display the message at the end, we have to use the Dispatcher to make sure the code that touches the UI executes back on the UI thread:

Dispatcher.BeginInvoke(() =>
    {
        var report = String.Format("Inserted {0:d} records in {1:0.00} seconds", 
            n, (double)sw.ElapsedMilliseconds / 1000);
        MessageBox.Show(report);

        Button_Start.IsEnabled = true;
    });

If we don’t do that, you get an exception.

SELECT Performance

What about the performance of reading records out of the database? The warnings I gave in the introduction to this piece about having appropriate keys configured if you are doing a SELECT with a filter on a column that is not the primary key are still valid. But even if you are simply reading all the records out of a table, whether you use ConfigureAwait(false) again has a huge impact.

Here’s the code you would probably write to read all the rows in our table and to load them into in-memory objects in an ObservableCollection<T> ready to display on the UI:

private async void Button_Select_Click(object sender, RoutedEventArgs e)
{
    if (db == null)
    {
        db = new SQLiteWinRT.Database(
            ApplicationData.Current.LocalFolder, "sqliteperf.db");

        await db.OpenAsync();
    }


    Stopwatch sw = Stopwatch.StartNew();
    int n = 0;
    Button_Select.IsEnabled = false;

    string sql = @"
        SELECT
            id , 
                Route_ID , 
                Service_ID, 
                Trip_ID, 
                Trip_Headsign,
                Direction_ID, 
                Block_ID, 
                Shape_ID, 
                Wheelchair_Accessible
            FROM TTC";
    var stmt = await db.PrepareStatementAsync(sql);

    ObservableCollection<TransportationTrip> tripCollection =
        new ObservableCollection<TransportationTrip>();

    while (await stmt.StepAsync())
    {
        var trip = new TransportationTrip()
        {
            ID = stmt.GetIntAt(0),
            RouteID = stmt.GetIntAt(1),
            ServiceID = stmt.GetIntAt(2),
            TripID = stmt.GetIntAt(3),
            TripHeadsign = stmt.GetTextAt(4),
            DirectionID = stmt.GetIntAt(5),
            BlockID = stmt.GetIntAt(6),
            ShapeID = stmt.GetIntAt(7),
            WheelchairAccessible = 
                stmt.GetIntAt(8) == 1 ? true : false,
        };

        tripCollection.Add(trip);
        n++;
    }

    var report = String.Format("Selected {0:d} records in {1:0.00} seconds",
        n, (double)sw.ElapsedMilliseconds / 1000);
    MessageBox.Show(report);

    Button_Select.IsEnabled = true;
}

Running this gives the following result:

SELECT-no-Await

2838 seconds! That sucks – big time.

Then do it again, but make these subtle changes:

while (await stmt.StepAsync().AsTask().ConfigureAwait(false))
{
    var trip = new TransportationTrip()
    {
        ID = stmt.GetIntAt(0),
        RouteID = stmt.GetIntAt(1),
        ServiceID = stmt.GetIntAt(2),
        TripID = stmt.GetIntAt(3),
        TripHeadsign = stmt.GetTextAt(4),
        DirectionID = stmt.GetIntAt(5),
        BlockID = stmt.GetIntAt(6),
        ShapeID = stmt.GetIntAt(7),
        WheelchairAccessible = stmt.GetIntAt(8) == 1 ? true:false,
    };

    tripCollection.Add(trip);
    n++;
}

Dispatcher.BeginInvoke(() =>
    {
        var report = String.Format("Selected {0:d} records in {1:0.00} seconds", 
            n, (double)sw.ElapsedMilliseconds / 1000);
        MessageBox.Show(report);

        Button_Select.IsEnabled = true;
    });

Which gives this result:

SELECT-await

That’s some improvement! Comparing the two:

Test Total Time (seconds) – SELECT 128981 records SELECT Time per record (ms) Records per second
SELECT 2838 22 45
SELECT with ConfigureAwait(false) 32.4 0.25 3980

That’s a huge improvement!

[WARNING: The timings quoted here are for running on the emulator. You should expect times on a real device to be very substantially slower.]

Conclusions

Some golden rules emerge from this:

  1. Use ConfigureAwait(false) when calling SqlWinRT async methods, particularly within repetitive looping such as INSERT or SELECT of a significant number of records. Remember that when you do so, your code will not resume on the same context it started on, so take appropriate measures to handle this.
  2. In addition to using ConfigureAwait(false), wrap large numbers of INSERTs in a single transaction to get the best performance.

The last learning from this is not specific to SqlWinRT: if you call async methods on a WinRT component, there is a significant overhead in switching back to the originating context. Try calling such a component using ConfigureAwait(false) – it may yield significant performance benefits.

Lastly – this was a test program. If you ever find yourself trying to read 128000 records into memory, I would suggest you have another think about your app design and whether you really need all those objects in memory Smile .