HttpContent instead of streams

Published on December 9, 2009

I think the HttpContent class is my favourite part of this library.  This class acts as a container for the content that you received or are about to send.

Handling returned content

When you do make an http request with this library, the body of the response is wrapped inside an HttpContent object. So, when you do:

var content = HttpClient.Get(“http://www.google.com”);

what you get back is an HttpContent object.  How you convert that into something useful, depends on what type of data the content object contains.  The HttpContent.ContentType property will tell you the Internet-media-type type of the data you received.

If you get back text/plain then you can access it like this,

var mytext = content.ReadAsString();

if you get application and application/octet-stream and you know what to do with the bytes, you can simply do

var mybytearray = content.ReadAsByteArray();

However, these examples are pretty primitive.  If you reference the DLL Microsoft.Http.Extensions you will find a variety of richer data extraction methods that have been implemented as extension methods on the HttpContent class.  So you can then do:

var xmlElement = content.ReadAsXElement()
var xmlReader = content.ReadAsXmlReader()

to access stuff that comes to you as application/xml.

One of the more sophisticated methods is ReadAsSyndicationFeed.  This method leverages the RSS/Atom wrappers that are provided by WCF’s System.ServiceModel.Web DLL.

var client = new HttpClient();
var response = client.Get("http://www.stackoverflow.com/feeds");
var feed = response.Content.ReadAsSyndicationFeed();
foreach (SyndicationItem item in feed.Items) {
    Console.WriteLine(item.Title.Text);
}

This example pulls an Atom feed from the front page of Stackoverflow.com.  This really shows the beauty of a standardized data format like Atom.  Those few lines of code above will work in so many places across the web, and now with Microsoft pushing the new OData standard which is based on the Atom Publishing Protocol, many more of the Microsoft products will expose data in this way. e.g. Sharepoint 2010, Azure.

For those of you who feel the burning desire to pull custom objects across the wire, you don’t have to feel ignored as these following methods will take care of all the deserialization work and return you a nice static type.

var customer = content.ReadAsXmlSerializable<Customer>()
var customer = content.ReadAsDataContract<Customer>()

and finally if you want to pull objects across the wire, but are offended by angle brackets, you can use curly braces too.

var customer = content.ReadAsJsonDataContract<Customer>()

The use of extension methods here is really quite elegant because it makes it really easy to add your own “ReadAs” methods and use them in a completely consistent way.  The fact that many of the provided extension methods are factored out into their own Dll means that you do not need to deploy that library, and you can use just your own extension methods.  This has the additional benefit of allowing you to use this library without taking a dependency on WCF if you don’t want to.

 

Sending Content

To send content you can use either PUT or POST and the way you prepare the content is identical.  The basic process looks like this:

var client = new HttpClient()
var content = HttpContent.Create(<whatever you want to send>);
client.Post(content); // or client.Put(content);

The only part that changes is how you create the HttpContent object.

Suppose you want to send some simple text

var content = HttpContent.Create(“Here is some content”, "text/plain");

or maybe just an array of bytes.

var content = HttpContent.Create(new byte[] { 1, 2, 3 }, "application/octet-stream");

How about sending a file?

var c = HttpContent.Create(new FileInfo(“myfile.zip”), "application/octet-stream");

If you are dealing with an existing API that expects a POST from an html form then you will need to post using the content-type application/x-www-form-urlencoded.  That is as easy as,

var c = HttpContent.Create(new HttpUrlEncodedForm() { { "a", "1" }, { "b", "2" } });

and for a more concrete example, twitter always makes a good test subject.  Here is how you do a status update,

var client = new HttpClient(); 
client.DefaultHeaders.Authorization = Credential.CreateBasic("username","password"); 
var form = new HttpUrlEncodedForm(); 
form.Add("status","Test tweet using Microsoft.Http.HttpClient"); 
var content = HttpContent.Create(form); 
var resp = client.Post("http://www.twitter.com/statuses/update.xml", content);

 

It is pretty easy to continue this pattern and create your own factory methods for converting your favourite data type into an HttpContent object.  There are are quite a few other nice features about the content object relating to how it manages the underlying stream, when it reads from the stream, if it buffers the stream and other such nitty gritty, but I’ll save those details for another day.  To keep track of the other articles I am attempting to write on the subject, you can see the summary post here.