Click here to Skip to main content
Click here to Skip to main content

ASP.NET MVC - SerializedDataResult

, 1 May 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Create a custom ASP.NET MVC ActionResult to return serialized data in JSON or XML format

Update - May 2012 

This code has been made obsolete by ASP.NET MVC 4 Web API, which does everything here and much more.   

Introduction

I recently developed an ASP.NET MVC application that uses jQuery to call JsonResult controller methods and display the data in the browser. When the application was finished, I realized that my JsonResult controller methods effectively constituted an API that allowed other applications to query the data behind my application, without any additional effort on my part. It was an "accidental API", but worked pretty well. I then got a request to return data as XML instead of JSON, and this is where I hit a bit of a wall with MVC.

ASP.NET MVC has several built-in ActionResult types, including one data serialization type: JsonResult. While JsonResult is awesome, it does not address the need to be able to return data in other serialization formats, especially XML. It would be nice to write one controller method that can return either JSON or XML, depending on what the user has requested. Some people have achieved this by branching within their controller methods, returning a JsonResult if X and an XmlResult (from MvcContrib) if Y. Others have created custom ActionFilters that detect the "accept-types" header from the user's request and decide what to return based on that.

Neither of these solutions particularly appeal to me. In the first case, branching based on a data format parameter or header value inside the controller method seems a bit ugly - you're repeating this if logic for every controller method that returns serialized data, and this logic could become quite complex and make your controller difficult to understand. In the second case, it seems logically incorrect to have a JsonResult class for returning JSON data, but switch to an ActionFilter when something more advanced is required - why not have another ActionResult type that fits in with existing pattern, but is more flexible? And finally in both cases, the controller signature uses the base ActionFilter type, instead of the more specific (and this preferable) JsonResult or XmlResult type.

To meet my requirements, I've created a class called SerializedDataResult that can return data in either JSON or XML format, depending on either explicit instructions within the controller method, or implicit instructions with the request querystring, form, or headers. There is also a helper method implemented as an extension to the controller class, similar to the Json method used to create JsonResult instances. The code is based on the JsonResult class (from the open-source ASP.NET MVC 3 library, thanks Microsoft!) and the XmlResult class (from the MvcContrib project), and inspired by the various attempts at solving this problem using ActionFilters.

Using the Code

There are two basic scenarios for using this code. In the first scenario, you know what format you want to return the data in, and you tell SerializedDataResult using the SerializedDataFormat enum.

// data will be returned in JSON format
public SerializedDataFormat JsonQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Json,
		null, null, null,
		SerializedDataRequestBehavior.AllowGet);
}

// data will be returned in XML format
public SerializedDataResult XmlQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Xml,
		null, null, null,
		SerializedDataRequestBehavior.AllowGet);
}

In the second scenario, the requesting user decides what format to return the data in. They can do this either in the querystring, form, or accept-type headers of the request.

// data will be returned in the format requested by the user, 
// or JSON if it can't be determined what format the user wants
public SerializedDataResult AutoQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(svc.GetQuote(code), 
		SerializedDataRequestBehavior.AllowGet);
}

SerializedDataResult will first check request fields in the querystring and form for a field named "format" (this is configurable). This field must have a value of 'xml' or 'json'. If it doesn't find a format field in the querystring or form, it will check the accept-types header value for recognized types, specifically 'text/xml' and 'application/json'. If one of these types is found, it does the obvious thing and returns data in the corresponding format. Finally, if it can't figure out what type the requesting user wants, it defaults to JSON.

e.g. http://www.example.com/StockMarket/Quote/ABC?format=xml - this will return a quote in XML format

// a more complex call to the Serialize helper method
// data will be returned in the format requested by the user, 
// or JSON if it can't be determined what format the user wants
public SerializedDataResult ComplexQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Auto,
		"dataformat", // request querystring / form field containing format
		"application/quoteserver", // content-type to put in response header
		Encoding.Unicode, // encoding type for response
		SerializedDataRequestBehavior.AllowGet);
}

Points of Interest

This ActionResult uses the RequestBehavior.AllowGet/DenyGet pattern from JsonResult and is explained by Phil Haack in this post. I nicked the logic for this out of the JsonResult code.

History

  • Feb 10 2010 - Version 1
  • Feb 11 2010 - Version 1.1 - Added some unit tests to project, took CSS and JavaScript files out of the sample, corrected content encoding for XML results

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

David Poirier
Software Developer (Senior)
Australia Australia
No Biography provided

Comments and Discussions

 
GeneralMy vote of 2 PinstaffMatthew Dennis10-Feb-11 12:52 
QuestionRecreating the wheel PinstaffMatthew Dennis10-Feb-11 12:52 
AnswerRe: Recreating the wheel PinmemberDavid Poirier10-Feb-11 13:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141030.1 | Last Updated 1 May 2012
Article Copyright 2011 by David Poirier
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid