REST in .NET Revisited
It’s been two months since I first took a look at implementing a RESTful service using the .NET framework. It’s been a busy time personally with the birth of our first child. During that time, I’ve done a bit of research, read some books, seen some presentations to get a pretty good handle on the options available. The other day I attended the July meeting of the Chicago .NET User’s Group. Scott Seely was the presenter, and he covered the four basic approaches for creating a RESTful .NET service. Scott’s co-authored book (Effective REST Services via .NET: For .NET Framework 3.5) covers these options, but I haven’t had a chance to pick it up yet, so this is pretty much my take on them.
Option 1: Use the ASP.NET MVC Framework
When I first read through Professional ASP.NET MVC 1.0 the thought of implementing a data access service with it popped into my head right away. A quick Google search shows that I’m not alone. Using the MVC framework feels like there is extra work being done when compared to the other options for a pure dataset-based interface. I could see this being a great option if you already have an MVC site up and running with content and you want to expose data as well. I’m pretty sure people are already doing this to expose XSS feeds and such for their site. As mentioned at the CNUG meeting, this is probably the best option if you already know ASP.NET MVC to a good degree and want to create a RESTful service very quickly. I would also assume that this isn’t the option with the highest performance. The “official” Microsoft recommendation is that ASP.NET MVC isn’t the proper choice for creating a RESTful data service; WCF or ADO.NET Data Services are.
Option 2: Use ADO.NET Data Services
ADO.NET Data Services sounded like it was a really good match when I first read it’s overview. We’re not using the Entity Framework, but that’s OK because it also supports custom data sources. There are also quite a few good postings on how to use various technologies with ADO.NET Data Services. I created a test project based on some sample code which just uses an in-memory data source. Implementing a read-only service is very easy and fast to do. I wasn't thrilled about the default output format of AtomPub, but it’s easy enough to change to JSON by adding an “accept-content: text/json” header in the request on the client side.
Where things got a little messy was implementing the rest of CRUD operations for the custom data source. Marc Gravell wrote a series of blog posts covering how to write the code required to fill out the rest of the CRUD operations, which really helped me gain an understanding of what is needed. Compared to the automatic implementation when using the Entity Framework, I would have liked to see less reflection involved. Granted, I didn't dig deep enough, or truly know enough to speak about a “better” way to do it, I just know that reflection isn't the fastest operation in the .NET Framework.
I do like the ability to perform additional filtering and manipulation of the data directly in the URL. I’m not sure it’s a feature I need or would use, but as I read somewhere, that’s kind of the beauty of it; someone else might. If I had a pure “expose a dataset but you can’t use SQL (tcp 1433)” scenario, then I would go with this option. The limiting factor is that you have to return an IQueryable or an IEnumerable for your results. For my project, this isn't an issue for about 80% of the calls that would be made. However, there are some calls where I want to return a stream of binary data.
I do like ADO.NET Data Services. There may be a day where I have a need for it. For now, it’s not the best fit.
Option 3: Use WCF
In .NET 3.5, Microsoft added a lot of functionality to WCF to easily create a RESTful service. I started with a pure WCF setup and was happy with the results. I also tried out the WCF REST Starter Kit. It felt like it complicated things more than I was expecting so I stopped using it. I prototyped out a portion of our service using WCF and started playing around with it. There is a lot of flexibility with controlling how the results are formatted. There’s also no limitation on what you can output. Just to goof around, I had one URL fire back a Silverlight application to be run. I also found it easy to get information for times when I got stuck, such as implementing authorization and authentication.
My plan was to implement our service using WCF until I learned about the last option.
Option 4: Use a custom HttpHandler in IIS/ASP.NET
I hadn't run across this option at all when starting my research. Scott had presented it at the CNUG meeting and ran through some sample code. The main benefit of this method is performance. Scott commented that the service he wrote for the MySpace REST service was originally written using WCF. It was processing about 4,000 RPS. When they re-wrote it using a custom HttpHandler, they were able to handle about 14,000 RPS. We didn't get details as to the exact nature of the work being done, but that’s a pretty significant improvement. Our service will never hit that level of traffic since it’s an intranet application, but we do care about good performance and lower CPU utilization.
The trade-off for the speed improvement is the extra code that needs to be written. WCF does a lot of tasks automatically for you, such as serializing the responses, setting up the UriTemplateTable, method routing, etc. With a custom HttpHandler, we get to do all of that ourselves. For me personally, the extra code isn't enough to make we want to switch back to WCF. I actually like the flexibility it offers. The core of the code is also common enough with the WCF version that if I run into an unforeseen problem, I can switch back to WCF quickly.
ASP.NET MVC – It’s already pretty RESTful, but it feels like you need to do too much when providing mostly data access
ADO.NET Data Services – A powerful way to host data over a service. In a pure data CRUD application, it’s a good way to go, especially if you’re using the Entity Framework.
WCF – The recommended method from Microsoft. Flexible with just enough built-in helper methods and features.
Custom HttpHandler – Very similar to the WCF approach, but closer to the wire. Just about complete control at the cost of more coding.
For now, I’m going to go with the HttpHandler. I think it’s going to best fit our needs and offer the most flexibility. Time to code!