I’ll qualify this post up front by say it is probably going to be more of a “rant” than most. That being said, I am very big fan of ASP.NET Web API, and am looking forward to see the enhancements coming in Web API 2.
In the current version of Web API, one of my biggest pet peeves is the usage of multiple complex objects within the Web API method signature is basically not allowed. If you are not too familiar with Web API usage, then right now you are probably asking “what the heck is he talking about”? Take a look at this standard Web API Post method:
First thing you’ll notice is that there are two complex objects in the signature. In this example I want to pass two completely different instances of the customer object to the method for comparisons and who knows what else. Unfortunately upon executing this, you’ll notice that “customerToCompare” is ALWAYS NULL. This is because only one complex object can be parsed using the model binder from the body for one request. In the above example I have specified “[FromBody]” attribute manually for the purpose of the demo, but it is not required as complex objects by default are always parsed from the body of the request. I could manually specify that a Customer should be parsed “[FromUri]”, but I think we can agree that’s not a good idea!
For performance reasons, the Web API request body is only allowed to be accessed and parsed “once”. So after the scan and parsing occurs of the request body for the “customer” parameter, all subsequent body parses will end in “NULL”.
To reiterate in Web API:
– Only ONE item can be attributed with “[FromBody]”
– Any number of items can be attributed with “[FromUri]”
The next legitimate comment I can already hear you making is that “I am simply using Web API for an unintended purpose”. There may be some merit in that if we assume that Web API was created for use in RESTful services only. Web API is at its core, simply a pure technology for dealing with HTTP requests. And on top of that REST is a pure architectural style for using on top of HTTP, and Web API is a prime technology used to implement this style. That being said, I have some very specific views, that Web API should be (and can be) a replacement for any other types of Web Services you have used in the past in .NET. No need to use .ASMX or WCF Web Services anymore, especially when Web API is SO SIMPLE and SO PURE in web communication.
I use Web API as a replacement for RPC, REST, and OData services; one technology for every style/specification. If an application I’m writing is internal only and there is no possible need for full REST architecture then I simply use RPC calls like I would have 5 years ago into an .ASMX service. Letting the requirements dictate the architecture I think is an easy lesson we should all be familiar with.
I won’t go any deeper here, but do check out this article:
While I have titled this “the solution” really, what we are talking about is a possible workaround for dealing with multiple complex objects in the signature.
The key in this workaround lies in using the “JObject” object apart of Newtonsoft.Json library. This objects gives us a concrete type specifically designed for working with JSON.
We simply adjust the signature to accept one complex object from the body, our “JObject”, which we have pluralized to “customers”. From here we will manually parse properties of the JSON object and use generics to hydrate the concrete “Customer” type. So a couple extra lines of code and I can parse as many complex objects as I want with relative ease. But honestly, I’m still not a big fan of this approach:
– One of the best things about Web API is how clean it is and how simple it is. I love that you can live and die by your method signatures for contracts to the API. In this example with JObject, I have no idea what the true contract of this method is simply by looking at the signature. I find it messy and a bit of a hack. That being said I do see true scenario’s where using a JObject allows you to be a lot more dynamic.
– While I am concerned about readability and maintainability of the API, realistically in this approach I have killed my full content negotiation functionality that we get for free from Web API. No matter what I decide to use for my “content-type” in the request, I will have an embedded JSON string within the content. That’s not so bad when I am only using JSON, but if it were a public API and someone wanted to use XML, they would basically be passing an XML payload with a JSON string inside of it.
On initial launch of Web API a while ago I heard rumblings of support for parsing the body more than once in future releases, but I have seen zero mention of it in Web API 2 as of yet. I will have to test it out and get back to you on that!