Introducing PortableRest 2.0 - Cross-Platform REST Client for .NET Apps
PortableRest 2.0 will finally RTM this week has finally released. Get it now! It's been a long road, and while I could have put it out as a "final" release no NuGet sooner, I wanted some apps to be using it without issue before I could be confident enough to stick a fork in this release. Since I've never blogged about it, I thought I'd take a bit to explain why it exists, and why you should use it.
Why I Built PortableRest
Earlier this year, I wanted to build some Windows Phone & Windows 8 applications to monitor the services we use here at AdvancedREI. Although I dislike some of the implementation details of RestSharp, overall I liked the idea, and have used it for some time (I built one of the first .NET client libraries for Twilio with it). But I had numerous concerns over taking a dependency on that platform for new projects:
- At the time, development on RestSharp had stagnated, and support on Windows Phone was limited at best. One of the services we used required XML payloads, and the Windows Phone client simply did not suport them. The Windows Phone version also did not support any kind of compression. They've released a new version since then, which may have adressed some of these issues... I'm not sure.
- I did not like how little control I ultimately had over the design of the objects for the service client in situations where I had no control over the server-side of the service. I didn't want to be hamstrung deigning bad client side APIs just because some numbskull had poor naming skills or had to adhere to ill-thought-out naming conventions.
- There were situations where the you would be unable to easily store service objects locally on the device, because client objects needed to implement different serializers for over-the-wire vs IsolatedStorage serialization.
- Large amounts of RestSharp are totally unnecessary with the advent of Microsoft.Net.HttpClient, which had just gone into beta when I started.
- I wanted to be able to write a single REST client library and use it on any Microsoft platform, without using any of the platform-specific techniques I had to resort to with XamlEssentials. At the time (and is still true today), RestSharp requires you to build separate libraries for each platform; there was no REST client with PCL support.
So with these issues identified, I set out to build a library that was mostly compatible with RestSharp, but solved all of these limitatations. The idea would be that you could remove RestSharp and add this library with minimal code changes, and get a significantly better developer experience (that would also consume less bandwidth).
Building It Out
In looking at what needed to be done to make all this happen, the first thing was that the HttpClient needed support for Compression. Morten Nielsen's work at providing compression support to the Windows Phone community has been legendary. But I needed Portable version, and his version used HttpClient but was not itself Portable, nor did it support Deflate compression. So I looked at the .NET compression libraries out there for options. It turned out that the .NET Framework used a native version of the ZLIB library interally, and that DotNetZip had a Silverlight port of that library already. It was trivial to convert the Silverlight port into a Portable version, and Zlib.Portable was born. Some quick additions to Morten's original concept plus the Zlib.Portable library, and HttpClient.Compression soon followed. Shortly thereafter, Microsoft released their own compression scheme for HttpClient, but for a while, HttpClient.Compression was the only way to get solid GZIP and DEFLATE support with the Microsoft.Net.Http library.
My next biggest problem was dealing with property naming. So I had this idea that JSON.NET would be the single point-of-contact for object serialization and de-serialization. This initially led to my contribution to JSON.NET for XML support in the Portable Class Libraries for PCLs targeting .NET 4.0.3 and later. But after I had done the work to get JSON.NET to support async/await and XML in Portable Class Libraries, there were several situations where JSON.NET just was not working out on the XML side. If I remember correctly, it had to do with objects mixing attributes and elements, or something like that.
A coding tenet I try very hard not to break is "Never reinvent the wheel unless you absolutely have to." In this case, I didn't want to have to create my own serialization systems, or make you decorate your models with attributes that served the same purpose as attributes already in the Framework. Since I also needed to be able to serialize the objects to the file system, and control how the over-the-wire properties were named, I settled on using DataContract notation for the object and property names, and using the XmlAttribute attribute to deal with the Xml serialization issue.
Now I know, DataContractSerialization is not the most efficient method for serializing... but it is the most consistently supported across platforms, transmission, and storage formats. Since JSON.NET recognizes DataContract-related attributes with its serialization, we can still leverage it for JSON payloads and get outstanding performance. But with the ability to handle compressed payloads, any issue with DataContractSerialization speed + XML is offset by the boost from using compression over the wire.
Unfortunately, this means that you still have to deal with some of the nuances of DataContractSerialization, but the system does its best to protect you from as many of these things as we can.
Putting PortableRest to use
The unit tests from the GitHub repository show some of the basics of using PortableRest. This first example shows how to build an annotate an object.
And this example shows how to build the Client.
Then calling the client is super-simple:
Wrapping It Up
There you have it. Our own New Relic Alerts app for Windows Phone uses a client library based on PortableRest, and I've been told a bunch of other apps in the Windows Phone Store use it as well. So download it off of NuGet today and post any issues or pull requests to GitHub. If you've got any apps using PortableRest, please let everyone know in the comments. Thanks, and happy coding!