ASP.NET Core MVC Fundamentals
Level: Intermediate
- MVC pattern: Model (data objects), View (HTML templates), Controller (request handlers)
- Request flow: Browser → Controller action → gets Model data → passes to View → View renders HTML
- Controller: Class handling HTTP requests (StudentsController, TeachersController)
- Controller base class:
public class StudentsController : Controller(includes View(), RedirectToAction(), etc.) - Action methods:
public IActionResult Index()handles HTTP request, returns HTML response - View (.cshtml): HTML template mixing C# and HTML (
@model List<Student>,@foreach (var s in Model)) - Model: Data passed from Controller to View (
return View(students)passes student list) - Model binding: Form data automatically converts to model (
Create(Student student)populated from POST form) - Tag helpers:
<input asp-for="Name">generates form fields bound to model properties - Routing: URL maps to Controller action (
/students/details/5→ StudentsController.Details(id: 5)) - ViewData/ViewBag: Flexible data passing Controller → View (
ViewData["Title"] = "Students") - School Management pages: StudentList (Index), StudentDetails, CreateStudent, EditStudent
- HTML form submission: POST to action, action validates, returns View with errors or redirects to success page
- CRUD workflow: Index (list) → Create (form) → POST Create (save) → Redirect → Details (view)
What is MVC?
Model-View-Controller architectural pattern.
- Model = Data (Student, Exam, Fee)
- View = HTML UI (Razor
.cshtmlfiles) - Controller = Request handler, business logic
User Request → Controller → Model → View → HTML Response
Project Structure
SMS.Web/
├── Controllers/
│ ├── StudentsController.cs
│ ├── ExamsController.cs
│ └── FeesController.cs
├── Views/
│ ├── Students/
│ │ ├── Index.cshtml
│ │ ├── Details.cshtml
│ │ ├── Create.cshtml
│ │ └── Edit.cshtml
│ ├── Shared/
│ │ ├── _Layout.cshtml
│ │ └── _ValidationScriptsPartial.cshtml
│ └── Home/
│ └── Index.cshtml
├── Models/
│ ├── Student.cs
│ ├── Exam.cs
│ └── ViewModels/
│ └── StudentViewModel.cs
├── Program.cs
└── appsettings.json
Controllers and Actions
Controller = class handling HTTP requests. Action = public method returning view or data.
using Microsoft.AspNetCore.Mvc;
public class StudentsController : Controller
{
private readonly IStudentService _service;
public StudentsController(IStudentService service)
{
_service = service;
}
// GET: /students
public async Task<IActionResult> Index()
{
var students = await _service.GetStudentsAsync();
return View(students);
}
// GET: /students/5
public async Task<IActionResult> Details(int id)
{
var student = await _service.GetStudentAsync(id);
if (student == null)
return NotFound();
return View(student);
}
// GET: /students/create
public IActionResult Create()
{
return View();
}
// POST: /students/create
[HttpPost]
[ValidateAntiForgeryToken]
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);
}
// GET: /students/edit/5
public async Task<IActionResult> Edit(int id)
{
var student = await _service.GetStudentAsync(id);
if (student == null)
return NotFound();
return View(student);
}
// POST: /students/edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Student student)
{
if (id != student.Id)
return NotFound();
if (ModelState.IsValid)
{
await _service.UpdateStudentAsync(id, student);
return RedirectToAction(nameof(Index));
}
return View(student);
}
// POST: /students/delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id)
{
await _service.DeleteStudentAsync(id);
return RedirectToAction(nameof(Index));
}
}
Views and Razor Syntax
View = Razor .cshtml file. Mix C# and HTML.
File: Views/Students/Index.cshtml
@model List<Student>
@{
ViewData["Title"] = "Students";
}
<h1>Students List</h1>
<a class="btn btn-primary" asp-action="Create">Add Student</a>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Roll Number</th>
<th>Class</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var student in Model)
{
<tr>
<td>@student.Name</td>
<td>@student.RollNumber</td>
<td>@student.ClassName</td>
<td>@student.Status</td>
<td>
<a asp-action="Details" asp-route-id="@student.Id">View</a>
<a asp-action="Edit" asp-route-id="@student.Id">Edit</a>
<form asp-action="Delete" asp-route-id="@student.Id" method="post" style="display:inline;">
<button type="submit" onclick="return confirm('Are you sure?');">Delete</button>
</form>
</td>
</tr>
}
</tbody>
</table>
Model Binding from Forms
Forms automatically bind to model properties.
File: Views/Students/Create.cshtml
@model Student
@{
ViewData["Title"] = "Create Student";
}
<h1>Add New Student</h1>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="RollNumber"></label>
<input asp-for="RollNumber" class="form-control" />
<span asp-validation-for="RollNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ClassName"></label>
<select asp-for="ClassName" class="form-control">
<option value="">Select Class</option>
<option value="10-A">10-A</option>
<option value="10-B">10-B</option>
<option value="11-A">11-A</option>
</select>
<span asp-validation-for="ClassName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Status"></label>
<select asp-for="Status" class="form-control">
<option value="Active">Active</option>
<option value="Inactive">Inactive</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Create</button>
<a asp-action="Index" class="btn btn-secondary">Cancel</a>
</form>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
POST binds form values to Student model automatically.
Tag Helpers
Replace HTML with smart tags. Generate correct URLs automatically.
| Tag Helper | Purpose |
|---|---|
asp-action | Action method name |
asp-controller | Controller name |
asp-route-id | Route parameter value |
asp-for | Property binding (label, input) |
asp-validation-for | Validation error message |
Layout and Shared Views
File: Views/Shared/_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"] - SMS</title>
<link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-controller="Home" asp-action="Index">SMS</a>
<button class="navbar-toggler" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-controller="Students" asp-action="Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-controller="Exams" asp-action="Index">Exams</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<script src="~/lib/jquery/jquery.min.js"></script>
<script src="~/lib/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>
In other views: @{ Layout = "_Layout"; }
Program.cs Setup
var builder = WebApplicationBuilder.CreateBuilder(args);
// Add MVC
builder.Services.AddControllersWithViews();
// Services
builder.Services.AddScoped<IStudentService, StudentService>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
app.Run();
Routing
Default route: {controller}/{action}/{id?}
Examples:
/students→ StudentsController.Index()/students/details/5→ StudentsController.Details(id=5)/students/edit/5→ StudentsController.Edit(id=5)
Key Takeaways
- MVC = separate concerns (Model, View, Controller)
- Controllers = handle requests and orchestrate
- Views = Razor templates with C# expressions
- Model binding = automatic form-to-object conversion
- Tag helpers = generate proper HTML and URLs
- Layout = shared header, nav, footer
Keep business logic in services, not controllers. Controllers orchestrate only.
Use ChatGPT, Claude, or Copilot to go deeper on ASP.NET Core MVC Fundamentals. Try these prompts:
"What's the difference between MVC and Web API?""How does model binding work?""What are tag helpers?""When should I use partials vs layouts?""Quiz me on ASP.NET Core MVC"
💡 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.