RESTful interfaces for web services are all the rage for many Web 2.0 sites. If you want to consume these in
a very simple fashion, LINQ to XML can do the job pretty easily in C#. If you go searching for help on this, youll find
a lot of incomplete solutions and fairly large toolkits and frameworks (guess how I know this) this quick article is meant to be
a no fluff just stuff approach to making this work. POCO Objects Lets assume you have
a Model that you want to suck data into from
a RESTful web service. Ideally this is
a Plain Old CLR Object, meaning it isnt infected
with any persistence or serialization goop. It might look something like this: public class Entry
{
public int Id;
public int UserId;
public DateTime Date;
public float Hours;
public string Notes;
public bool Billable;
public override string ToString()
{
return String.Format("[{0}] User: {1} Date: {2} Hours: {3} Notes: {4} Billable {5}", Id, UserId, Date, Hours,
Notes, Billable);
}
}
Not that this isnt
a completely trivial object. Lets look at the API for the service.
RESTful HTTP Service
In this case, its TickSpots API,
with the following sample output:
<?xml version="1.0" encoding="UTF-8"?>
<entries type="array">
<entry>
<id type="integer">24</id>
<task_id type="integer">14</task_id>
<user_id type="integer">3</user_id>
<date type="date">2008-03-08</date>
<hours type="float">1.00</hours>
<notes>Had trouble
with tribbles.</notes>
<billable>true</billable> # Billable is an attribute inherited from the task
<billed>true</billed> # Billed is an attribute to track whether the entry has been invoiced
<created_at type="datetime">Tue, 07 Oct 2008 14:46:16 -0400</created_at>
<updated_at type="datetime">Tue, 07 Oct 2008 14:46:16 -0400</updated_at>
# The following attributes are derived and provided for informational purposes:
<user_email>
[email protected]</user_email>
<task_name>Remove converter assembly</task_name>
<sum_hours type="float">2.00</sum_hours>
<budget type="float">10.00</budget>
<project_name>Realign dilithium crystals</project_name>
<client_name>Starfleet Command</client_name>
</entry>
</entries>
Im assuming in this case that I dont necessarily care about all of the data fields the service is returning I just need some of them for my applications purposes. Thus, you can see there are more elements in the <entry> XML than I have in my Entry class.
Get The XML
with C#
The next step is to get the XML. The following snippet does the heavy lifting once you pass it the appropriate URL:
protected XElement GetResponse(string uri)
{
var request = WebRequest.Create(uri) as HttpWebRequest;
request.UserAgent = ".NET Sample";
request.KeepAlive = false;
request.Timeout = 15 * 1000;
var response = request.GetResponse() as HttpWebResponse;
if (request.HaveResponse == true && response != null)
{
var reader = new StreamReader(response.GetResponseStream());
return XElement.Parse(reader.ReadToEnd());
}
throw new Exception("Error fetching data.");
}
This is adapted from the Yahoo Developer article on Web Service REST calls. Once you have the XML, the last step is to get the data back as your POCO.
Use LINQ-To-XML to Deserialize POCOs from XML
This is done via the following code:
public IEnumerable<Entry> List(DateTime startDate, DateTime endDate)
{
string additionalParameters =
String.Format("start_date={0}&end_date={1}",
startDate.ToShortDateString(),
endDate.ToShortDateString());
string uri = BuildUrl("entries", additionalParameters);
XElement elements = GetResponse(uri);
var entries = from e in elements.Elements()
where e.Name.LocalName == "entry"
select new Entry
{
Id = int.Parse(e.Element("id").Value),
UserId = int.Parse(e.Element("user_id").Value),
Date = DateTime.Parse(e.Element("date").Value),
Hours = float.Parse(e.Element("hours").Value),
Notes = e.Element("notes").Value,
Billable = bool.Parse(e.Element("billable").Value)
};
return entries;
}
For completeness, heres the BuildUrl method for my TickSpot API wrapper:
// Change these to your settings
protected const string projectDomain = "DOMAIN.tickspot.com";
private const string authParams = "
[email protected]&password=MyTickSpotPassword";
protected string BuildUrl(string apiMethod, string additionalParams)
{
if (projectDomain.Contains("DOMAIN"))
{
throw new ApplicationException("You must update your domain in ProjectRepository.cs.");
}
if (authParams.Contains("MyTickSpotPassword"))
{
throw new ApplicationException("You must update your email and password in ProjectRepository.cs.");
}
return string.Format("https://{0}/api/{1}?{2}&{3}", projectDomain, apiMethod, authParams, additionalParams);
}
Thats it! Now go forth and consume XML and map it to classes you actually want to work
with. Have fun!
Did you know that DotNetSlackers also publishes .net articles written by top known .net Authors? We already have over 80 articles in several categories including Silverlight. Take
a look: here.