Introduction
In ASP.NET MVC the controller is the component that receives requests from the client, performs some actions and returns results back to the client.
The controller typically returns results as data or views. The ASP.NET MVC 4 beta comes with a new type of controller
called ApiController that helps to create RESTful applications in an easy and efficient way. So having two types of controllers now experts advise to use the default controller for returning views and the ApiController for returning data. Since the default controller
itself capable of delivering both data as well as views I don't see many benefits by introducing the new ApiController.
It would be great if the default controller has been extended to add the RESTful features into the MVC framework.
In most of the MVC applications we have controllers that return both data and views. The problem is that from a single
controller action we can't return both data as well as views. Many times we end up writing two controller actions one to return view
and the other to return data in either JSON or XML format (for AJAX calls). Having two controller actions makes more chances of code duplication.
It would be really nice if we can return both data as well as view from a single action itself. Doing this stuff is quite difficult in ApiController
because it doesn't have capabilities to return views. So we left with the option of using the default controller to achieve that.
Controller vs. ApiController
Although both types of controllers looks very similar they are not even derived from the same base class or implements the same interface (at-least in the beta version). The default controller derives from the abstract class ControllerBase (which implements IController)
and the ApiController implements the interface IHttpController. From the default controller we can return both data and view but
from the ApiController we can return only data.
Plan
So at the higher level here is what we are going to accomplish. We are going to make the controller actions to return either data or view based upon
the request parameters. If the request is an AJAX request we are going to return data in specific format based upon the Accept header.
In case of non-AJAX requests, if the url contains "type" parameter in the query-string with value as either "xml" or "json" then we are going to return data
in that format else we are going to return view.
Strategy
First I thought of creating a custom action result but I soon understood returning views from action results going to be very difficult and its
because the methods that does the job exists as protected methods in Controller. So one better idea is extending the default controller with adding
our methods that performs what we need. All the other controllers in the application should derive from the extended controller.
Implementation
Lets create our custom controller BaseController by extending the default controller.
public class BaseController : Controller
{
protected virtual ActionResult Result(object data)
{
}
protected virtual string GetContentType()
{
}
}
Our BaseController has couple of methods. The Result() method which will be called from the controller actions to return data or view.
The GetContentType() method determines the response type, for data it is either XML or JSON and for view it is HTML.
Here is the implementation of both methods.
protected virtual ActionResult Result(object data)
{
ActionResult actionResult;
switch (GetContentType().ToLower())
{
case "xml":
actionResult = new XmlResult(data);
break;
case "json":
actionResult = new JsonResult
{
Data = data,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
break;
default:
actionResult = View(data);
break;
}
return actionResult;
}
protected virtual string GetContentType()
{
var type = Request.QueryString["type"];
if (string.IsNullOrEmpty(type))
{
if (Request.IsAjaxRequest())
type = Request.Headers["Accept"].Contains("application/json")
? "json"
: "xml";
else
type = "html";
}
return type;
}
The Result() method invokes the GetContentType() to know the response content-type whether it is "xml", "json" or "html". Based upon the type it instantiates
and returns the corresponding ActionResult. The XmlResult is a custom action result that returns the model as XML (you can see the implementation in the attached source).
Here is an example controller with a single action that returns data (XML, JSON) or view (HTML).
public class MotorController : BaseController
{
public ActionResult Index()
{
return Result(new CarRepository().GetAll());
}
}
The below table list down the different action results returned from the above controller action for different addresses and headers.
| Address |
Is Ajax? |
Action Result |
| http://localhost:7777/motor |
No |
Returns view |
| http://localhost:7777/motor?type=xml |
No |
Returns data in XML format |
| http://localhost:7777/motor?type=json |
No |
Returns data in JSON format |
| http://localhost:7777/motor |
Yes |
Returns data in XML format |
| http://localhost:7777/motor?type=xml |
Yes |
Returns data in XML format |
| http://localhost:7777/motor?type=json |
Yes |
Returns data in JSON format |
http://localhost:7777/motor
Accept: "appliation/json"
|
Yes |
Returns data in JSON format |
http://localhost:7777/motor
Accept: "appliation/xml"
|
Yes |
Returns data in XML format |
Download Sample
I'm a software developer from south tip of India. I spent most of the time in learning new technologies. I've a keen interest in client-side technologies especially JavaScript and admire it is the most beautiful language ever seen.
I like sharing my knowledge and written some non-popular articles. I believe in quality and standards but blames myself for lagging them.
I believe in small things and they makes me happy!