Thursday, 16 June 2011

Agile RESTful Json in Silverlight

Following on from my previous post (Consuming POX in Silverlight), here’s a simple example of consuming a Json data service.

ScreenShot012

Data file (exposed via Http Handler on Web Server)

[
{
name:'Shredded Wheat',
price:4.95,
description:'Two per serving with skimmed milk',
calories:650
},
{
name:'Fresh Fruit Salad',
price:5.95,
description:'Strawberries, bananas, apples and pears',
calories:400
},
{
name:'Scrambled Eggs on Toast',
price:3.95,
description:'Two eggs on two slices of wholewheat toast',
calories:300
},
{
name:'Bacon Roll',
price:2.5,
description:'Three slices of lean bacon in a granary roll',
calories:600
},
{
name:'Homestyle Breakfast',
price:12.95,
description:'Two eggs, bacon, sausage, toast and orange juice',
calories:950
}
]

Http Handler (on Web Server)

using System.IO;
using System.Web;

namespace AgileREST.Web
{
public class FoodService : IHttpHandler
{

public void ProcessRequest(HttpContext context)
{
var dataPath = HttpContext.Current.Server.MapPath("Food.json");

using (var reader = new StreamReader(dataPath))
{
var result = reader.ReadToEnd();
context.Response.ContentType = "text/json";
context.Response.Write(result);
}
}

public bool IsReusable
{
get
{
return false;
}
}
}
}

Mapping (on the client)

namespace AgileREST
{
public class Food
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public int Calories { get; set; }
}
}

Service Call (on the client)

using System;
using System.Collections.Generic;
using System.Json;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;

namespace AgileREST
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}

void webClientForJson_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null) return;

// first option
JsonArray foods = (JsonArray)JsonArray.Load(e.Result);
var query = from food in foods
select new Food()
{
Name = (string)food["name"],
Price = (decimal)food["price"],
Description = (string)food["description"],
Calories = (int)food["calories"]
};
listboxFoodJson.ItemsSource = query.ToList();

// second option
// for implicit serialisation requires identical case sensitive name across Json and C# food objects)
//DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<Food>));
//List<Food> foods = (List<Food>) jsonSerializer.ReadObject(e.Result);
//listboxFoodJson.ItemsSource = foods;
}

private void btnGetFoodJson_Click(object sender, RoutedEventArgs e)
{
WebClient webClientForXml = new WebClient();
webClientForXml.OpenReadCompleted += webClientForJson_OpenReadCompleted;
webClientForXml.OpenReadAsync(new Uri(HtmlPage.Document.DocumentUri, "FoodService.ashx"));
}
}
}

Data binding (on the client)

<UserControl x:Class="AgileREST.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="700">

<UserControl.Resources>
<DataTemplate x:Key="itemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="tbName"
Width="170"
Text="{Binding Path=Name}" />
<TextBlock x:Name="tbPrice"
Width="50"
Text="{Binding Path=Price}" />
<TextBlock x:Name="tbDescription"
Width="300"
Text="{Binding Path=Description}" />
<TextBlock x:Name="tbCalories"
Width="50"
Text="{Binding Path=Calories}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Width="600" Margin="10">
<TextBlock Text="Json Example" Margin="5" />
<StackPanel x:Name="ColumnDescriptions" Orientation="Horizontal" Margin="5" >
<TextBlock Text="Name" Width="170" />
<TextBlock Text="Price" Width="50" />
<TextBlock Text="Description" Width="300" />
<TextBlock Text="Calories" Width="50" />
</StackPanel>
<ListBox x:Name="listboxFoodJson"
Height="150"
Margin="5"
ItemTemplate="{StaticResource itemTemplate}" />
<Button x:Name="btnGetFoodJson"
Height="50"
Margin="5"
Click="btnGetFoodJson_Click"
Content="Get Food From Json Service" />
</StackPanel>
</Grid>
</UserControl>

You can download the source code from the following link:


http://stevenhollidge.com/blog-source-code/AgileREST.zip

No comments:

Post a Comment