Skip to main content

Controllers and Action Results

Level: Intermediate

ℹ️ What You'll Learn
  • Action method: public async Task<IActionResult> GetStudent(int id) handles request, returns response
  • IActionResult types: View() (HTML), Json() (API response), RedirectToAction() (navigate to another action), BadRequest(), NotFound()
  • View(): Return HTML generated from .cshtml template (return View(student) passes data)
  • View("ViewName"): Return specific view template (default: action name)
  • RedirectToAction(): Navigate to another action (return RedirectToAction("Index") after saving)
  • BadRequest(): Return HTTP 400 (validation failed)
  • NotFound(): Return HTTP 404 (student not found)
  • [HttpGet]: Handle GET request (display form)
  • [HttpPost]: Handle POST request (form submission, process data)
  • Route parameters: Details(int id) captures URL parameter (/students/details/5 → id=5)
  • Model binding: Create(Student student) automatically populates Student from form data
  • ModelState.IsValid: Check if form validation passed before saving
  • ViewBag/ViewData: Weakly-typed data (ViewBag.Title = "Students", ViewData["Count"])
  • TempData: Temporary data for redirect (user feedback message after save)
  • School Management CRUD: Index (list students), Details (show one), Create (form), POST Create (save), Edit (edit form), POST Edit (update), Delete (confirm), POST Delete (remove)
  • Return View with errors: return View(student) shows form again with validation messages if invalid

Action Method Basics

Action = public method in Controller. Returns IActionResult (View, JSON, Redirect, etc).

public class StudentsController : Controller
{
// GET: /students
public async Task<IActionResult> Index()
{
var students = await _service.GetStudentsAsync();
return View(students); // Returns Index.cshtml with students
}

// GET: /students/details/5
public async Task<IActionResult> Details(int id)
{
var student = await _service.GetStudentAsync(id);
return View(student);
}

// GET: /students/create
public IActionResult Create()
{
return View(); // Empty form
}

// POST: /students/create
[HttpPost]
public async Task<IActionResult> Create(Student student)
{
if (ModelState.IsValid)
{
await _service.CreateStudentAsync(student);
return RedirectToAction(nameof(Details), new { id = student.Id });
}
return View(student);
}
}

IActionResult Types

MethodPurposeSends
View()Render Razor templateHTML
View(model)Render with dataHTML with data
PartialView()Render partial templateHTML fragment
Redirect(url)Redirect to URL302 status
RedirectToAction(action)Redirect to action302 status
RedirectToRoute(route)Redirect to route302 status
Json(data)Return JSONJSON data
Ok(data)HTTP 200 OKJSON/Content
BadRequest()HTTP 400 errorError response
NotFound()HTTP 404 errorNot found response
Unauthorized()HTTP 401 errorAuth required
Forbid()HTTP 403 errorAccess denied
StatusCode(code)Custom HTTP statusCustom status
Content(text)Plain textText response
File(bytes)Download fileFile download

Returning Views

public async Task<IActionResult> ListStudents()
{
var students = await _service.GetStudentsAsync();

// Explicitly named view
return View("StudentList", students);

// Default: look for StudentList.cshtml or Index.cshtml
}

Default view names: {ActionName}.cshtml or Shared/{ActionName}.cshtml

Route Parameters

Parameters auto-bound from route.

// Route: {controller}/{action}/{id?}
public async Task<IActionResult> Details(int id)
{
// id bound from URL
var student = await _service.GetStudentAsync(id);
return View(student);
}

// Route: /students/details/10 → id = 10

Query String Parameters

// GET: /students?className=10-A&status=Active
public async Task<IActionResult> Filter(string className, string status)
{
var students = await _service.FilterAsync(className, status);
return View(students);
}

POST and Forms

[HttpPost] attribute for POST requests. Prevent CSRF: [ValidateAntiForgeryToken]

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Student student)
{
if (!ModelState.IsValid)
return View(student); // Re-display form with errors

await _service.CreateStudentAsync(student);
return RedirectToAction(nameof(Index));
}

Form must include anti-forgery token:

<form asp-action="Create" method="post">
@Html.AntiForgeryToken()
<!-- form fields -->
</form>

JSON Responses

Return JSON for AJAX or mobile clients.

[HttpPost]
public async Task<IActionResult> CreateJson(Student student)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);

var created = await _service.CreateStudentAsync(student);
return Json(new { success = true, id = created.Id });
}

JavaScript:

fetch('/students/createjson', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Ravi', rollNumber: 'SMS-2024-001' })
})
.then(r => r.json())
.then(data => console.log(data));

Redirects

// Redirect to action
return RedirectToAction(nameof(Details), new { id = student.Id });

// Redirect to route
return RedirectToRoute("default", new { controller = "Home", action = "Index" });

// Redirect to URL
return Redirect("https://nexcoding.in");

Redirect = HTTP 302 (temporary). URL changes in browser.

Status Code Responses

public async Task<IActionResult> GetStudent(int id)
{
var student = await _service.GetStudentAsync(id);

if (student == null)
return NotFound(); // 404

if (student.Status == StudentStatus.Inactive)
return BadRequest("Student is inactive"); // 400

return Ok(student); // 200 with data
}

Response Headers

public IActionResult Download()
{
var fileBytes = System.IO.File.ReadAllBytes("student.pdf");

return File(
fileBytes,
"application/pdf",
"students.pdf"
); // Triggers download
}

ActionResult Filters

Execute before/after action.

[Authorize] // Only logged-in users
public IActionResult AdminPanel()
{
return View();
}

[Authorize(Roles = "Admin")] // Only admins
public IActionResult DeleteAll()
{
return View();
}

Key Takeaways

  • Action = public method handling request
  • IActionResult = flexible response type
  • View(model) = render HTML with data
  • RedirectToAction = go to another action
  • ModelState.IsValid = form validation passed
  • StatusCode responses = 200, 400, 404, 500
  • POST + CSRF token = secure form submission
💡 Controller Tip

Keep actions simple. Delegate logic to services.

🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on Controllers and Action Results. Try these prompts:

  • "What's the difference between View and PartialView?"
  • "When should I use RedirectToAction vs Redirect?"
  • "How does model binding work from route parameters?"
  • "When should I return JSON vs View?"
  • "Quiz me on controllers"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

nexcoding.in