Monthly Archives: June 2013

Creating Data-Driven Windows 8 Apps from Microsoft’s Grid Template using REST APIs for Designers

By Don Burnett Microsoft Blend MVP (2012-2013)

Part One: Getting Started with Live Data In your App from and existing REST style Web Service…

One of the things that has been difficult with Windows 8 Apps for designers is getting at data to model it and use it in an App. With Silverlight and WPF Microsoft’s Blend has provided us with a bunch of really great tools to help us model data in an app and done the heavy lifting to make it easy to use that data directly when designing the user experience. Unfortunately when Blend was refocused to be a part of the Visual Studio family of products, the same care was not given to make data available to the “app designer” as part of a Windows Store App.

We can still work with Data but a lot of the heavy lifting has to be done by ourselves. Many apps today bring in data from an outside source, and really just consume data from some other source out there. This article will walk through the process from the designer perspective about getting data into an “app”. In this article we will walk through the process of replacing the data model in one of Microsoft’s sample GRID templates with Data from a REST data source.

In the past in as a WPF, Silverlight, or Windows Phone app designer we could just do the following steps in Blend to model our data.

  1. From The Data Tab in Blend: select Import Sample Data from XML

  2. Add the URL to our REST data API query.

    In this case I am going to look at some transit data in European SIRI format from a REST api. I just name my data source and in the XML file path I just place the URL to the data source query..

    http://api.SIRIDATA.org/rest/stopmonitoring/?monitoringref=2903

    If we looked at this data by pasting the URL in a WEB browser the results returned would look like this (an XML document)

  3. After doing this Blend creates a schema and gives me a look at the fields and I can drag and drop live data onto my design surface from this panel. The image below shows us that panel with the schema for the data source along with data types that can be adjusted based on the types of data.

This certainly made designing from data and consuming data from an API easier. You could then just drag and drop anything in that panel to data bind live data right into your interface. In fact it was pure heaven for designers because we could see changes in real-time. With Windows 8 much of this has changed for Windows Store apps. Designers no longer have this power in Blend for Windows Apps due to a number of refactoring’s of the .NET framework (aka WinRT) to support as the framework was optimized for more asynchronous delivery models and targeting different devices out there, including ARM tablets and others. However ALL is *NOT* lost and hopefully we will be able to step through this new process for you.

So how can we address this in Windows 8 as a Windows Store App? There are just a few more steps necessary. Let’s start by using one of the Grid Templates. Normally I would do this in Blend first, but in this release with the new manifests and settings I am going to do this part in Visual Studio and create a GRID template app called TransitApp.. I will assume you have already created this for this walk-thru..

Our process will include:

  1. Create a portable class library so that we can build assemblies that work on all Microsoft platforms, thus reducing the amount of work required to move the data layer between potential platforms that we may wish to create versions of our app for.

Platform

.NET for Windows Store apps

.NET Framework 4.0 through 4.5

Silverlight 4 and 5

Windows Phone 7.0 through 8.0

Windows Azure

X-Box

 

  1. Make Calls to a REST Service with System.Net.Http.HttpClient
  2. Replace the sample data source and make Asynchronous Calls to it
  3. Add items to our master-detail Windows Store Grid Template

Step One: Creating the Portable Class Library for our Data Layer

In the past, to share code between a Web service and a WPF application, we might create a Class Library project. To do this with Windows Store apps we must create a portable class library. This will allow us to build assemblies that work across the spectrum of Windows projects and share entities between a REST service and the Windows Store app (.NET for Windows Store apps) without code duplication on either client or server platforms. At the time of this writing, we are required to use Visual Studio 2012. So let’s walk through this process now. This assumes you have already created your own Windows Store App from the Grid Template.

In a VS 2012 Windows Store App Solution (XAML)

  • Select File.. Add ..New Project…
  • Select Templates ..Visual C# in the left pane.Select Portable Class Library.


  • Enter your desired name for the library in the Name textbox. I’ll use TransitApp.Entities because both my app and a REST service will share the entities defined in this portable class library.
  • Click OK.. When the Add Portable Class Library dialog box appears select only the following target frameworks:
    • .NET Framework 4.5
    • .NET for Windows Store apps


  • Visual Studio will add the new TransitApp.Entities Portable Class Library to the solution.
  • To verify things are correct, go to and open References, there will be a reference to .NET Portable Subset.
  • Verify that the portable class library includes an initial class, Class1 which we will delete since it is auto-generated.
  • Delete Class1
  • Add a new interface, IEntity:

 
 

namespace TransitApp.Entities
{
public interface IEntity
{
string Id { get; set; }
}
}

 

  • Add a new class, Entity, that implements the previously created IEntity interface:
    {
    public class Entity : IEntity
    {
    public string Id { get; set; }
    }
    }

     

  • Add a new class, Item, that inherits from Entity:

 
 

namespace TransitApp.Entities
{
public class Item : Entity
{
public string Title { get; set; }
public string Subtitle { get; set; }
public string Description { get; set; }
public string Content { get; set; }
public string MainPage { get; set; }
}
}

 

  • Add a new class, Group, that inherits from Entity and groups items:

 
 

namespace TransitApp.Entities
{
using System.Collections.Generic;

public class Group : Entity
{
public string Title { get; set; }
public string Subtitle { get; set; }
public string Description { get; set; }
public string MainPage { get; set; }
public IEnumerable<Item> Items { get; set; }
}
}

  • That’s all we have to do and we are ready to go with our new portable class library
  • Next Go back to the TransitApp project/solution that generates our Windows Store app
  • Right click on References in Solution Explorer
  • Select Add Reference…
  • Inside the Reference Manager, Click on Solution..Projects in the left pane, check TransitApp.Entities and click OK. This allows the Windows Store app to use all of the entities defined in our portable class library.

 

Step Two: Calling our REST Service with System.Net.Http.HttpClient

Next we will consume our REST service in our Grid Template based transit app by using the new asynchronous methods provided by the new System.Net.Http.HttpClient.

Go to the TransitApp project/solution

Add a new Services folder.


Add a new interface, IGroupService, within the Services folder. The following is the code for IGroupService:

    namespace TransitApp.Services

{
using System.Collections.Generic;
using System.Threading.Tasks;

    //// TransitApp.Entities (Portable Class Library)
using Entities;

    public interface IGroupService
{
Task<IEnumerable<Group>> GetAll();
}
}


Create a subfolder named Implementation within the Services folder.

Add a new class, GroupService, within Services\Implementation.

Implement the previously created interface:


namespace TransitApp.Services.Implementation
{
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

    //// TransitApp.Entities (Portable Class Library)
using Entities;

    public class GroupService : IGroupService
{
private const string RestServiceUrl = “http://localhost:46037/api/&#8221;;

    public async Task<IEnumerable<Group>> GetAll()
{
var client = new HttpClient
{
BaseAddress = new Uri(RestServiceUrl)
};

//// Add and support a header for JSON
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));

    //// Retrieve groups and items

var response = await client.GetAsync(“groups”);

    //// Exception throw if problems
response.EnsureSuccessStatusCode();

    
//// In case you need date and time properties

const string dateTimeFormat = “yyyy-MM-ddTHH:mm:ss.fffffffZ”;
var jsonSerializerSettings = new DataContractJsonSerializerSettings
{
DateTimeFormat = new DateTimeFormat(dateTimeFormat)
};

    var jsonSerializer = new DataContractJsonSerializer(
typeof(Group[]),
jsonSerializerSettings);

    var stream = await response.Content.ReadAsStreamAsync();
return (Group[]) jsonSerializer.ReadObject(stream);
}
}
}

The GroupService class has a GetAll method that uses the async modifier to return a Task<IEnumerable<Group>>. This method is called with the await keyword. You will be able to retrieve an IEnumerable<Group> without having to worry about a Task wrapper.

The GetAll method does the following:

Creates a new instance of the System.Net.Http.HttpClient class and sets its base address to our REST service URL.

var client = new HttpClient
{
BaseAddress = new Uri(RestServiceUrl)
};

Adds and accepts a header for JSON for the HttpClient instance.

    
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));

Make the REST call to GET api/groups with an asynchronous execution by using the HttpClient.GetAsync method. The method returns a Task<HttpResponseMessage> that the await keyword develops into an HttpResponseMessage.

var response = await client.GetAsync(“groups”);

Call the EnsureSuccessStatusCode for the HttpResponseMessage instance. This method throws an exception if something goes wrong.

response.EnsureSuccessStatusCode();

Creates a new instance of DataContractJsonSerializerSettings and sets a value for the DateTimeFormat property. This isn’t all there is to deserializing JSON with REST calls in Windows Store apps but it will get you started.


const string dateTimeFormat = “yyyy-MM-ddTHH:mm:ss.fffffffZ”;
var jsonSerializerSettings = new DataContractJsonSerializerSettings
{
DateTimeFormat = new DateTimeFormat(dateTimeFormat)
};


Create a new DataContractJsonSerializer instance specifiying and array of Group as a type and the previously explained settings.


var jsonSerializer = new DataContractJsonSerializer( typeof(Group[]), jsonSerializerSettings);

    

Call the ReadAsStreamAsync method for the Content property of the response that is an instance of HttpContent. The method returns Task<System.IO.Stream>. The call is made with an asynchronous execution by using the await keyword that creates the response into a System.IO.Stream instance.


var stream = await response.Content.ReadAsStreamAsync();

The code returns the results of the call to the ReadObject for the DataContractJSonSerializer instance that receives the previously read System.IO.Stream as a parameter. The code returns an array of Group (Group[]).

return (Group[]) jsonSerializer.ReadObject(stream);


Note: It is necessary to make sure that the App manifest provides outbond access to the Internet to consume the REST service with HttpClient.

In the TransitApp Visual Studio project/solution:

Double click on Package.appxmanifest and then select the Capabilities page, and make sure Internet (Client) is checked.

 

Step Three: Replacing the sample data source included in our Grid app template


Next we are go to replace the sample data source included in the Grid app template with the results of calling our previously created GetAll method to retrieve all the groups and their items from the REST service.


Process:

 

Remove all the code in the SampleDataSource constructor from the TransitApp project Template. We absolutely have to do this because the constructor was adding the sample groups and items.

Add a new static asynchronous method to the SampleDataSource class (RefreshDataSource):

public static async Task RefreshDataSource()
{
var groupService = new GroupService();
var allGroups = await groupService.GetAll();
foreach (var group in allGroups)
{
var sampleDataGroup = new SampleDataGroup(
group.Id,
group.Title,
group.Subtitle,
“Assets/LightGray.png”,
group.Description);

_sampleDataSource.AllGroups.Add(sampleDataGroup);

if (group.Items != null)
{
foreach (var item in group.Items)
{
sampleDataGroup.Items.Add(new SampleDataItem(
item.Id,
item.Title,
item.Subtitle,
“Assets/DarkGray.png”,
item.Description,
item.Content,
sampleDataGroup));
}
}
}
}

Go to App class (App.xaml.cs) and change the code for the OnLaunched event handler so that it calls the previously created SampleDataSource.RefreshDataSource with an asynchronous execution when the app’s previous state is ApplicationExecutionState.NotRunning.

protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;

    // Don’t initialization if content exists,
// Make sure window is active

if (rootFrame == null)
{
// Create a Frame to act as the navigation context, and navigate to first page
rootFrame = new Frame();
//Associate the frame with a SuspensionManager key
SuspensionManager.RegisterFrame(rootFrame, “AppFrame”);
    if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// Restore the saved session state when appropriate
try
{
await SuspensionManager.RestoreAsync();
}
catch (SuspensionManagerException)
{
//Something went wrong restoring state.
//
}
}
else if (args.PreviousExecutionState == ApplicationExecutionState.NotRunning)
{
//// Retrieve all the groups by making a call to the REST service
try
{
await Data.SampleDataSource.RefreshDataSource();
}
catch (Exception ex)
{
////Something went wrong write your code here…
}
}
    // Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn’t restored navigate to the first page,
// configure the new page by passing information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(GroupedItemsPage), “AllGroups”))
{
throw new Exception(“Failed to create initial page”);
}
}
// Ensure the current window is active
Window.Current.Activate();
}

 

 

To Be Continued..


 

Advertisements