Create REST API using ASP.NET MVC that speaks both Json and plain Xml

UPDATE: There’s a newer article on this that shows how to create a truly RESTful API and website using the same ASP.NET MVC code.

www.codeproject.com/KB/aspnet/aspnet_mvc_restapi.aspx

ASP.NET MVC Controllers can directly return objects and collections, without rendering a view, which makes it quite appealing for creating REST like API. The nice extensionless Url provided by MVC makes it handy to build REST services, which means you can create APIs with smart Url like “something.com/API/User/GetUserList”

There are some challenges to solve in order to expose REST API:

  • Based on who is calling your API, you need to be able to speak both Json and plain old Xml (POX). If the call comes from an AJAX front-end, you need to return objects serialized as Json. If it’s coming from some other client, say a PHP website, you need to return plain Xml.
  • Similarly you need to be able to understand REST, Json and plain Xml calls. Someone can hit you using REST url, someone can post a Json payload or someone can post Xml payload.

I have created an ObjectResult class which takes an object and generates Xml or Json output automatically looking at the Content-Type header of HttpRequest. AJAX calls send Content-Type=application/json. So, it generates Json as response in that case, but when Content-Type is something else, it does simple Xml Serialzation.

image

Here’s the ObjectResult that you can use from Controllers to return objects and it takes care of proper serialization method. Above shows the Json serialization, which is quite simple.XmlSerialization is a bit complex though:

image

Things to note here:

  • You have to force UTF8 encoding. Otherwise it produces UTF16 output.
  • XML Declaration is skipped because that’s not quite necessary. Wastes bandwidth. If you need it, turn it on.
  • I have turned on indenting for better readability. You can turn it off to save bandwidth.

Some of you might be boiling inside looking at my obscure coding style. I love this style! I am spoiled by jQuery. I wish there was a cQuery. I actually started writing one, but it never saw day light just like my hundred other open source attempts.

Now back to Object Serialization, we got the serialization done. Now you can return objects from Controller easily:

image

You can use the test web project to call these methods and see the result:

image

So far you have seen simple object and list serialization. A best practice is to return a common result object that has some status, message and then the real payload. It’s handy when you only need to return some error but no object or list. I use a common Result object that has three properties – ErrorCode (0 by default means success), Message (a string data type) andData which is the real object.

image

When you want to return only a result with error message, you can do this:

image

This produces a result like this:

image

No payload here. So, the return format is always consistent. Those who are consuming service can write a common Xml or Json parsing code to consume both success and failure response. Those who are building API for their website, I humbly request you to return consistent response for both success and failure. It makes our life so easier.

So, far we have only returned objects and lists. Now we need to accept Json and Xml payload, delivered via HTTP POST. Sometimes your client might want to upload a collection of objects in one shot for batch processing. So, they can upload objects using either Json or Xml format. There’s no native support in ASP.NET MVC to automatically parse posted Json or Xml and automatically map to Action parameters. So, I wrote a filter that does it.

image

This filter intercepts calls going to Action methods and checks whether client has posted Xml or Json. Based on what has been posted, it uses DataContractJsonSerializer or simpleXmlSerializer to convert the payload to objects or collections.

You use this attribute on Action methods like this:

image

The attribute expects a parameter name where it stores the deserialized object/collection. It also expects a root type that it needs to pass to the deserializer. If you are expecting a single object, specify typeof(SingeObject). If you are expecting a list of objects, specify an array of that object like typeof(SingleObject[])

You can test the project live at this URL:

http://labs.dropthings.com/MvcWebAPI

The code is also available at:

http://code.msdn.microsoft.com/MvcWebAPI

Enjoy!

————

Here’s an Eid gift for my believer brothers. Check out this amazing sitewww.quranexplorer.com/. You will get online recitation, translation – verse by verse. The recitation of Mishari Rashid is something you have to listen to to believe. Try these two recitations to see what I mean:

Sura 97 – Verse 1
Sura 114 – Verse 1

Press the “Play” icon at bottom left (hard to find).

kick it on DotNetKicks.com

32 Comments

  1. Excellent article. I loved it. I made REST architecture b4 MVC came in picture and it was so difficult but this has solved all problems.

    Thanks Omar

  2. I commend your effort but you really need to remove all traces of the word REST from this post. Your implementation is sooooooo far from being RESTful it is scary. I'm not saying there is anything wrong with your implementation, it's just not REST. It violates most of the REST constraints. Don't believe me? Ask the guy who invented the term REST. roy.gbiv.com/…/rest-apis-must-be-hypertext-driven

  3. Hi Darrel,

    Good observation! I would like to understand why you think my mention of REST is wrong here.

    Here's what I tried to convery:

    1) You can create REST like API using ASP.NET MVC. I do not see why this statement is wrong.

    2) You can accept JSON and XML payload on RESTful resources via GET and POST protocol. I do not see why this statement is wrong.

    REST requires that every resource must have a uniquely identifiable URI. For ex, someapi.com/API/GetUser/Scott gives you a person named 'Scott'. Now, my implementation gives you further control on the representation of 'Scott' resource by allowing you to consume 'Scott' in either Json or POX format.

    I suppose if I made the URL like someapi.com/API/User/Scott and based on GET and POST, decide what action to invoke (GetUser or UpdateUser), that would look more like RESTful. But in any way, what URI you provide, how you expose and consume resources are entirely up to you. I am just enabling you to offer two more representation for your resources.

  4. Hi Omar,

    There is a nice article from Joe Gregorio:

    http://www.xml.com/…/restful-web.html

    which describes the basic mechanisms for REST based services.

    Basically, your URIs will look like this:

    /API/User

    and only the HTTP methods will be different for Create,Retrieve,Update,Delete (Post,Get,Put,Delete)

    A nice addition is this article from the same author:

    http://www.xml.com/…/restful-web.html

    Regards,

    Stephan

  5. Nice article Omar, I picked up some ideas. If you are interested in a truely RESTful web service using ASP.Net MVC I have been writing a series of posts at shouldersofgiants.co.uk/blog on this subject. I too had created multiple representations (including XHTML and Help). I also supportted POST overloading. Cheers!

  6. not yet an advance developer, so much of your article are too much for me, but stuff u had on ajax and loading and compression, seems like something my side needs to explore,, thanks for the break down explanation,

    also thanks for the into to quranexplorer

  7. Hi Omar,

    I'm developing an http web API (MVC).Your article has been useful to me. I appreciate.

    Regards,

    Paul.

  8. Hi Omar,

    I have been struggling with XML Serialization for a few weeks now, your article was just the help I needed, thank you.

    The Quran Explorer is very cool too. Sura 97 verse 1 is beautiful.

  9. Hi Omar,

    it's great to find out the way to post JSON data to an action. But, if i want to use more than one JSON object parameters, how can it possible. For instance,

    public ActionResult UploadUser (User user, Group group){}

    We are using the AjaxPro.net library for the existing projects and want to shift to the asp.net MVC for the newer ones, but how to deal with this kind of problems are concerning us. Any idea?

  10. Can someone explain the logic of this line:

    if ((context.HttpContext.Request.ContentType ?? string.Empty).Contains(“application/json”))

    {

    It's my understanding that the coalesce operator identifies a null value, and if so, return an alternate value.

    How it's being used looks like:

    If ContentType is null, than string.Empty.Contains(“…”);

    Am I missing something as this doesn't look proper to me. Thanks for clarifying.

  11. @Danny: I believe the author wrote this code only to avoid an “Object reference is not set to an instance of an object..” exception.

    Yes, you are right, the string.Empty.Contains .. doesn't carry enough sense, but still it returns a false (which is perfectly correct in this scenairo) rather opening a possiblity of an exception raise.

    @Omar: IMHO, does this really comply with the definition of REST? I agree with Stephan's comment here.

  12. Moim, I agree the sample I showed is not done as per the true REST specification. But the libraries presented here that the sample uses do facilitate REST implementation. So, if you overlook the sample I made and take the libraries I made for facilitating REST over ASP.NET MVC, there's no issue with making a REST API yourself.

  13. Hi Omar,

    Thanks so much for the insightful article. It was a great read.

    However, my question is about how scalable this approach is. I would like to know if you've done some stress testing and what were the results? Did it scale well?

    About Darrel's comment, I would actually be surprised if I didn't find any comment claiming that this is RESTful. But I think you clarified it in your response to Darrel's comment.

  14. Thank you for submitting this cool story – Trackback from PimpThisBlog.com

  15. Wiil i be able to consume this rest api via a php application?If yes how.I want should be able to consume this in the application itself not by typing the url in the browser.

  16. Thank you for some great code.. I have translated it all to vb.net and will post it here when i get it up on the webb :)

    (I am a beginenr with ASP.net MVC – therefore this question might me very simple)

    How can i tell it to render the normal view, if the request is not json/xml?
    Or is all my normal Return View() sent as text/xml?
    I might be thinking wrong…

  17. Ops, forgot to answer Sagar…
    Yeah you can, thats the idea with an API.

    You do it just liek you use any other REST API (Might be wrong, but twitter, flickr etc)

    google for something like “PHP use external API” or “PHP using rest API”.

    Goodluck :)

  18. What’s the best way to secure the resulting application? Can we take advantage of the [authorize] attribute? How does the requesting application send credentials?

  19. i downloaded your file MVCWebAPI and it gives me an error

    “CS1928: ‘System.Web.Mvc.HtmlHelper’ does not contain a definition for ‘ActionLink’ and the best extension method overload ‘System.Web.Mvc.Ajax.AjaxExtensions.ActionLink(System.Web.Mvc.AjaxHelper, string, string, System.Web.Mvc.Ajax.AjaxOptions)’ has some invalid arguments”

    how can i solve this ? thanks! :)

  20. Hi, i’ve tested this code and it is not getting the content-type of the request it always returns xml and never json. What should i do to make it work?

    if ((context.HttpContext.Request.Contents?? String.Empty).Contains(“application/json”))

    always returns false because: Contents = “”

  21. hi thanks for this article. it helped a lot

    I am following your code and have another requirment. I am dealing with only XML.
    I have a XmlResult (like your objectResult). The same code there in ExecuteResult(), just with one addition.
    I am transforming the xml to a different form of xml using xslt. My question
    Is it best practice to do it here or on the filter?
    How to do it on Filter?

  22. How to deseralize this objectResut instance. I am using this concept and I want to do Unit testing of what I get from controller action methods. It can send error object or correct reponse object. I am able to see them in fiddler. but I need to do Unit Test to verify Json result or xml result from code.

Leave a Reply