Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Returning data and view from a single controller action

, 23 Jul 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
IntroductionIn 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

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)
	{
		// returns data as either xml,  json or view.
	}

	protected virtual string GetContentType()
	{
		// returns the content type of response
	}
}

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

License

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

Share

About the Author

After2050
Software Developer Trigent Software Private Limited
India India
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!
Follow on   Twitter

Comments and Discussions

 
GeneralMy vote of 4 Pinmembersariqkhan21-Nov-12 1:33 

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 | Mobile
Web01 | 2.8.141015.1 | Last Updated 23 Jul 2012
Article Copyright 2012 by After2050
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid