MVC Architecture
π― What You'll Learn
- What is MVC
- Model-View-Controller pattern
- MVC vs Web API
- Setting up MVC
- Folder structure
- Request pipeline
What is MVC?
MVC (Model-View-Controller) is a design pattern for building web applications that separates concerns into three components:
- Model: Data and business logic
- View: User interface (HTML)
- Controller: Handles requests and coordinates Model and View
MVC separates your application into three distinct layers, making it easier to maintain, test, and scale.
The MVC Pattern
Model
The Model represents your data and business logic.
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
}
View
The View is the HTML template that displays data to the user.
@model List<Product>
<h1>Products</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model)
{
<tr>
<td>@product.Name</td>
<td>@product.Price</td>
<td>@product.Quantity</td>
</tr>
}
</tbody>
</table>
Controller
The Controller handles HTTP requests and returns views.
public class ProductsController : Controller
{
private readonly InvenTrackDbContext _context;
public ProductsController(InvenTrackDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var products = await _context.Products.ToListAsync();
return View(products);
}
}
Request Flow
- User navigates to
/Products - Routing maps URL to
ProductsController.Index() - Controller retrieves data from database
- Controller passes data to View
- View renders HTML with data
- HTML is returned to the browser
MVC vs Web API
| Aspect | MVC | Web API |
|---|---|---|
| Purpose | Server-rendered HTML | JSON/XML data |
| Base Class | Controller |
ControllerBase |
| Returns | IActionResult (Views) |
ActionResult<T> (Data) |
| Use Case | Traditional web apps | SPAs, mobile apps |
| Attributes | Route attributes optional | [ApiController] required |
Setting Up MVC
Create MVC Project
dotnet new mvc -n InvenTrack.Web
cd InvenTrack.Web
dotnet run
Configure Services
var builder = WebApplication.CreateBuilder(args);
// Add MVC services
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure middleware
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// Map default route
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Folder Structure
InvenTrack.Web/
βββ Controllers/
β βββ HomeController.cs
β βββ ProductsController.cs
βββ Models/
β βββ Product.cs
β βββ ErrorViewModel.cs
βββ Views/
β βββ Home/
β β βββ Index.cshtml
β βββ Products/
β β βββ Index.cshtml
β β βββ Details.cshtml
β βββ Shared/
β βββ _Layout.cshtml
β βββ _ViewStart.cshtml
βββ wwwroot/
β βββ css/
β βββ js/
β βββ lib/
βββ Program.cs
βββ appsettings.json
Key Folders
| Folder | Purpose |
|---|---|
Controllers/ |
MVC controllers |
Models/ |
View models and entities |
Views/ |
Razor view templates |
Views/Shared/ |
Shared layouts and partials |
wwwroot/ |
Static files (CSS, JS, images) |
View Discovery
ASP.NET Core searches for views in this order:
Views/{ControllerName}/{ActionName}.cshtmlViews/Shared/{ActionName}.cshtml
// ProductsController.Index() looks for:
// 1. Views/Products/Index.cshtml
// 2. Views/Shared/Index.cshtml
public IActionResult Index()
{
return View(); // Searches for Index.cshtml
}
// Specify view name
public IActionResult Index()
{
return View("ProductList"); // Searches for ProductList.cshtml
}
Complete InvenTrack Example
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
public string Category { get; set; } = string.Empty;
}
public class ProductsController : Controller
{
private readonly InvenTrackDbContext _context;
public ProductsController(InvenTrackDbContext context)
{
_context = context;
}
// GET: /Products
public async Task<IActionResult> Index()
{
var products = await _context.Products.ToListAsync();
return View(products);
}
// GET: /Products/Details/5
public async Task<IActionResult> Details(int id)
{
var product = await _context.Products.FindAsync(id);
if (product == null)
return NotFound();
return View(product);
}
}
@model List<Product>
<h1>InvenTrack Products</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Quantity</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var product in Model)
{
<tr>
<td>@product.Name</td>
<td>@product.Category</td>
<td>$@product.Price</td>
<td>@product.Quantity</td>
<td>
<a asp-action="Details" asp-route-id="@product.Id">Details</a>
</td>
</tr>
}
</tbody>
</table>
Best Practices
- Separation of concerns: Keep Models, Views, and Controllers separate
- Thin controllers: Move business logic to services
- View models: Use DTOs for views, not domain models
- Async actions: Use async/await for database operations
- Dependency injection: Inject services into controllers
- Naming conventions: Follow ASP.NET Core conventions
Key Takeaways
- MVC: Model-View-Controller design pattern
- Model: Data and business logic
- View: HTML templates (Razor)
- Controller: Handles requests, returns views
- AddControllersWithViews(): Registers MVC services
- MapControllerRoute(): Configures routing
- View discovery: Views/{Controller}/{Action}.cshtml
- Server-rendered: HTML generated on server
You now understand MVC architecture! In the next section, we'll explore Controllers for Viewsβaction methods, action results, and passing data to views.