I’ve been starting to explore iPhone development lately. At first I was taking my time at learning at Objective C which went fine for a while but one of the guys on the project was asking if I could help build some apps for Project Nimbus, translation: build stuff fast.
We talked about MonoTouch.NET which is basically a framework that will allow you to code apps with .NET. JOY!!
First a quick intro about Project Nimbus: as Chewy would put it, it’s basically a supermarket for data here in Singapore. The team is hard at work at securing data from all sorts of providers. They currently have Hungry Go Where, Land Transport Authority, National Environment Agency, and National Library Board onboard as data providers, and i know they have quite a few more coming. What this means for developers is that if they have a great idea, they don’t have to go out by themselves with these big agencies and possibly spend tons of money on acquiring the data. If you want to find out more, check out http://projectnimbus.org/about/ for more information. They also very keen on getting input from developers as to what types of data they think would be useful, as well as feedback on the project as well. If you’re interested, the about page has a link to contact them 🙂
So back to my application. Right now, I’m figuring out how to actually get the data from the service. Looking at this entry, they actually provide a link to the data that’s returned when you make a call to the service. Check out the post, and towards the end, you’ll find a few links that shows how the data looks like. First we create a webrequest to the URL that gives me the dataset we want. In this case, we want to get access to the NowcastSet i.e. current weather. The service actually gets authentication from the headers so we add these two keys & values. We then make the request and read it into a string for parsing later on.
Next, if we look at the dataset that’s returned, we see that it makes use of a few namespaces. To make things WHOLE lot easier for us, we’ll use one of the cool features of the .NET Framework which I LOVE called LINQ to XML. If you want to find out more, check out http://msdn.microsoft.com/en-us/library/bb387098.aspx. Let’s first add the System.Xml.Linq namespace in order to use it’s classes.
We can now add a our XNamespaces:
The following stuff is just magic. With just one statement using LINQ to XML, we’re able to parse the xml string without having to use xpath or regex, etc. And, if you read the statement, it’s actually pretty descriptive of what it is trying to accomplish.
Given the structure of our sample data, we see that we’re essentially getting elements from entry.content.properties.
Note that the following line is just to make things a bit easier to read.
[cc lang=’csharp ]
let weather = item.Element(atomNS + “content”).Element(mNS + “properties”)
[/cc]
You can also just do the following and remove the let line, though I find it a bit more confusing to understand at first glance.
[cc lang=’csharp ]
from weather in XElement.Parse(resStr.Descendants(atomNS + “entry”).Elements(atmonNS + “content”).Elements(mNS + “properties”)
[/cc]
This is the full code:
[cc lang=’csharp’ ]
public List GetWeatherFromNimbusNEA(string AccountKey, string UniqueUserID)
{
System.Net.WebRequest wr = HttpWebRequest.Create(“http://api.projectnimbus.org/neaodataservice.svc/NowcastSet”);
wr.Headers.Add(“AccountKey”,AccountKey);
wr.Headers.Add(“UniqueUserID”,UniqueUserID);
wr.Method = “GET”;
WebResponse res = wr.GetResponse();
string resStr = new System.IO.StreamReader(res.GetResponseStream()).ReadToEnd();
XNamespace atomNS = “http://www.w3.org/2005/Atom”;
XNamespace dNS = “http://schemas.microsoft.com/ado/2007/08/dataservices”;
XNamespace mNS = “http://schemas.microsoft.com/ado/2007/08/dataservices/metadata”;
List results = (
from item in XElement.Parse(resStr).Descendants(atomNS + “entry”)
let weather = item.Element(atomNS + “content”).Element(mNS +”properties”)
select new WeatherEntry() {
Area = weather.Element(dNS +”Area”).Value,
Condition = weather.Element(dNS +”Condition”).Value,
Lat = weather.Element(dNS + “Latitude”).Value,
Lon = weather.Element(dNS + “Longitude”).Value }
).ToList();
return results;
}
[/cc]
It’s an hour after the end of the MIX10 Keynote. I started watching the video on my Mac partition so I couldn’t download the tools straight away. After it was over, I rebooted, uninstalled my pre-RC bits and installed the tools for Windows Phone 7 Series (which you can find here), fired it up and created a new Windows Phone List Application:
Since this is mainly a ProjectNimbus post, I won’t dive into how to build the WP7 app but there’s a new training kit up on channel 9 http://channel9.msdn.com/learn/courses/WP7TrainingKit/ if you want to learn more. I did make a few tweaks in my code since the original code wasn’t doing downloads asynchronously (which it should, to improve your apps performance and not lock the UI). So how does my code look now?
[cc lang=”csharp”]
public void GetWeatherFromNimbusNEA(string AccountKey, string UniqueUserID)
{
WebClient wc = new WebClient();
wc.Headers[“AccountKey”] = AccountKey;
wc.Headers[“UniqueUserID”] = UniqueUserID;
wc.DownloadStringCompleted +=new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri(“http://api.projectnimbus.org/neaodataservice.svc/NowcastSet”));
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string resStr = e.Result;
XNamespace atomNS = “http://www.w3.org/2005/Atom”;
XNamespace dNS = “http://schemas.microsoft.com/ado/2007/08/dataservices”;
XNamespace mNS = “http://schemas.microsoft.com/ado/2007/08/dataservices/metadata”;
var results = (
from item in XElement.Parse(resStr).Descendants(atomNS + “entry”)
let weather = item.Element(atomNS + “content”).Element(mNS + “properties”)
select new WeatherEntryViewModel()
{
Area = weather.Element(dNS + “Area”).Value,
Condition = weather.Element(dNS + “Condition”).Value,
Lat = weather.Element(dNS + “Latitude”).Value,
Lon = weather.Element(dNS + “Longitude”).Value
}
);
foreach (var r in results)
{
Items.Add(r);
}
}
[/cc]
It’s practically the same code except I switched to the WebClient which Silverlight developers are already familiar with to download the string asynchronously. Once the results are returned, I add them to an observable collection which I have data-bound my UI Elements to.
[cc lang=”csharp”]
Items = new ObservableCollection
[/cc]
The result is a basic list like application that displays weather information:
I’m excited about the WP7 platform and it’s definitely going to be a focus in my upcoming TechFriday posts! Next thing on my learning list is to share code between my two application platforms, iPhone and WP7. One thing is for sure though, I’m very happy with Project Nimbus as well because it provides a lot of data that I can already start playing around with. Kudos to the team!
2 Responses to “Consuming Data from Nimbus Using LINQ to XML on iPhone + WP7!”
Preston
I followed your codes and i faced an TargetInovationException. The inner exeception was that an execption occured during a WebClient request. the exeption occured at the line string resStr = e.Result;
Homo_sapien_dudo
The full error code:
{System.Reflection.TargetInvocationException: An exception occurred during the operation, making the result invalid. Check InnerException for exception details. —> System.Net.WebException: An exception occurred during a WebClient request. —> System.NotSupportedException —> System.NotSupportedException: Specified method is not supported.
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
— End of inner exception stack trace —
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
— End of inner exception stack trace —
— End of inner exception stack trace —
at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at System.Net.DownloadStringCompletedEventArgs.get_Result()} System.Exception {System.Reflection.TargetInvocationException}