Action Methods
An action decides what the browser receives: a page, some JSON, a file download, a redirect or an error. Choosing the right ActionResult makes your app behave correctly for users and for search engines.
On this page · 6 min · Beginner
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Beginner
- Updated
- Oct 29, 2026
Related tutorials
Learning objectives#
- Return the right ActionResult for each situation
- Restrict actions to GET or POST
- Return JSON safely from MVC 5
- Send files and status codes
Explanation#
Actions usually return ActionResult (or a more specific type). The helper methods on Controller build the results: View(), PartialView(), Content(), Json(), File(), Redirect(), RedirectToAction(), HttpNotFound() and new HttpStatusCodeResult(code).
[HttpGet] and [HttpPost] restrict which HTTP method an action answers. Two actions can share a name — Create() for GET shows the form and Create(model) for POST saves it.
Json(data) uses JavaScriptSerializer. For GET requests you must pass JsonRequestBehavior.AllowGet; MVC 5 blocks JSON over GET by default because of an old JSON-hijacking attack on arrays.
File(bytes, contentType, fileDownloadName) sends a download with a Content-Disposition header. RedirectToAction sends a 302 to another action’s URL, built from the routes.
[ActionName("delete")] exposes a method under a different name, which helps when GET and POST versions need the same URL but C# needs different signatures.
Syntax#
return View(model); // HTML page
return Content("text", "text/plain"); // raw text
return Json(data, JsonRequestBehavior.AllowGet); // JSON for GET
return File(bytes, "text/csv", "orders.csv"); // download
return RedirectToAction("Index"); // 302
return HttpNotFound(); // 404
return new HttpStatusCodeResult(400, "Bad id"); // any status
Code example: One controller, many kinds of results#
// Controllers/CatalogController.cs
using System.Net;
using System.Text;
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class CatalogController : Controller
{
// GET /Catalog/Price/1 → plain text
public ActionResult Price(int id)
{
if (id <= 0) return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "id must be positive");
if (id > 3) return HttpNotFound();
return Content(quot;Product {id} costs {id * 20} rupees", "text/plain");
}
// GET /Catalog/Info/2 → JSON
public ActionResult Info(int id)
{
var product = new { Id = id, Name = "Notebook", Price = 60.5m, Tags = new[] { "paper", "a4" } };
return Json(product, JsonRequestBehavior.AllowGet);
}
// GET /Catalog/Export → file download
public ActionResult Export()
{
var csv = "Id,Name,Price\n1,Gel Pen,20\n2,Notebook,60.5\n";
return File(Encoding.UTF8.GetBytes(csv), "text/csv", "products.csv");
}
// GET /Catalog/Old → permanent redirect
public ActionResult Old()
{
return RedirectToActionPermanent("Price", new { id = 1 });
}
// POST /Catalog/Remove/2 only
[HttpPost]
[ActionName("Remove")]
public ActionResult RemoveConfirmed(int id)
{
return RedirectToAction("Price", new { id });
}
}
}
GET /Catalog/Price/2
200 OK
Product 2 costs 40 rupees
GET /Catalog/Price/9
404 Not Found
GET /Catalog/Price/0
400 id must be positive
GET /Catalog/Info/2
200 OK
Content-Type: application/json; charset=utf-8
{"Id":2,"Name":"Notebook","Price":60.5,"Tags":["paper","a4"]}
GET /Catalog/Export
200 OK
Content-Disposition: attachment; filename=products.csv
Id,Name,Price
1,Gel Pen,20
2,Notebook,60.5
GET /Catalog/Old
301 Moved Permanently → /Catalog/Price/1
GET /Catalog/Remove/2
404 Not Found
POST /Catalog/Remove/2
302 Found → /Catalog/Price/2This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- Price validates the id: 0 gives 400 with a reason, 9 gives 404, and 2 gives plain text.
- Info returns Json(...), which serialises the anonymous object with JavaScriptSerializer — decimals stay as numbers and property names keep their PascalCase.
- Export sends bytes with Content-Disposition: attachment, so the browser downloads products.csv.
- Old answers 301 Moved Permanently, which tells browsers and search engines to update their links.
- RemoveConfirmed only accepts POST and is exposed as Remove, so a GET to /Catalog/Remove/2 returns 404 while the POST redirects.
Real-world use case#
An order-management app adds an “Export to Excel (CSV)” button: one action builds the CSV with a StringBuilder and returns File(…), and the browser downloads it with the right file name.
Common mistakes#
return Json(data) in a GET action throws “This request has been blocked because sensitive information could be disclosed…”. Pass JsonRequestBehavior.AllowGet when the data is safe to return to GET requests.
Refreshing the page resubmits the form. Redirect with RedirectToAction (the Post/Redirect/Get pattern).
Content("Not found") returns 200 OK, so caches and search engines treat it as a real page. Use HttpNotFound() or HttpStatusCodeResult.
Best practices#
- Pick the most specific result: NotFound, BadRequest, Redirect
- Use [HttpPost] for anything that changes data
- Use RedirectToActionPermanent for moved pages (SEO)
- Return view models or DTOs in JSON, not EF entities
Remember this#
ActionResult = what the browser gets.
Json + GET needs JsonRequestBehavior.AllowGet.
Changes data? [HttpPost] and redirect afterwards.
Practice exercise#
Your task: Write a Download action that returns a text file named receipt-{id}.txt containing “Receipt for order {id}”, and returns 404 for ids above 1000.
Need a hint?
Show solution
// Controllers/ReceiptsController.cs
using System.Text;
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class ReceiptsController : Controller
{
public ActionResult Download(int id)
{
if (id > 1000) return HttpNotFound();
var text = quot;Receipt for order {id}";
return File(Encoding.UTF8.GetBytes(text), "text/plain", quot;receipt-{id}.txt");
}
}
}
GET /Receipts/Download/42 200 OK Content-Disposition: attachment; filename=receipt-42.txt Receipt for order 42 GET /Receipts/Download/5000 404 Not Found
Mini quiz#
Which helper returns a 404 in MVC 5?
Want more? Practise all ASP.NET MVC MCQs · ASP.NET MVC interview questions
My notes#
Saved in this browser.