ASP.NET Core MVC Tutorial
Cross-platform web apps with middleware, DI, Razor, Entity Framework Core and Identity.
- Topics
- 42
- Full lessons
- 42
- Est. hours
- ~9
- Interview Qs
- 27
Overview
ASP.NET Core is the modern, cross-platform, open-source web framework for .NET. ASP.NET Core MVC adds controllers and Razor views on top of its middleware pipeline.
Dependency injection, configuration and logging are built in. Apps run on Windows, Linux, Docker and cloud platforms such as Azure App Service.
What you will learn
- Configure the app in Program.cs and the middleware pipeline
- Build controllers, Razor views and view components
- Use built-in dependency injection and configuration
- Persist data with Entity Framework Core and secure it with Identity
Prerequisites
You will get the most from this track if you already know:
Learning path
The recommended sequence, from beginner to advanced. Each stage builds on the one before.
- 1Foundations · 7 topics · BeginnerIntroduction to ASP.NET Core MVC · ASP.NET Core Architecture · Project Creation · Program.cs · Middleware · Request Pipeline · Routing
- 2Controllers & Views · 5 topics · Beginner → IntermediateControllers · Action Results · Razor Views · Layouts and Partial Views · View Components
- 3Models · 3 topics · IntermediateModel Binding · Model Validation · Data Annotations
- 4App Infrastructure · 5 topics · IntermediateDependency Injection · Configuration · appsettings.json · Environment-Specific Settings · Logging
- 5Data Access · 9 topics · IntermediateEntity Framework Core · ADO.NET · SQL Server Integration · Database-First Approach · Code-First Approach · Migrations · CRUD Operations · Repository Pattern · Service Layer
- 6Security · 4 topics · AdvancedAuthentication · ASP.NET Core Identity · Authorization Policies · Session and Cookies
- 7Production · 9 topics · AdvancedFile Uploads · Caching · Exception Handling · Unit Testing · Performance Optimization · Security · IIS Deployment · Docker Deployment · Complete E-Commerce Project
Complete topic list
42 topicsFoundations
7 topics- Introduction to ASP.NET Core MVCBeginner6m
- ASP.NET Core ArchitectureBeginner6m
- Project CreationBeginner6m
- Program.csBeginner5m
- MiddlewareBeginner6m
- Request PipelineBeginner6m
- RoutingBeginner6m
Controllers & Views
5 topics- ControllersBeginner6m
- Action ResultsBeginner6m
- Razor ViewsBeginner6m
- Layouts and Partial ViewsBeginner6m
- View ComponentsIntermediate6m
Models
3 topics- Model BindingIntermediate7m
- Model ValidationIntermediate7m
- Data AnnotationsIntermediate6m
App Infrastructure
5 topics- Dependency InjectionIntermediate7m
- ConfigurationIntermediate6m
- appsettings.jsonIntermediate5m
- Environment-Specific SettingsIntermediate5m
- LoggingIntermediate6m
Data Access
9 topics- Entity Framework CoreIntermediate7m
- ADO.NETIntermediate8m
- SQL Server IntegrationIntermediate6m
- Database-First ApproachIntermediate7m
- Code-First ApproachIntermediate6m
- MigrationsIntermediate6m
- CRUD OperationsIntermediate8m
- Repository PatternIntermediate7m
- Service LayerIntermediate7m
Security
4 topics- AuthenticationAdvanced8m
- ASP.NET Core IdentityAdvanced6m
- Authorization PoliciesAdvanced7m
- Session and CookiesAdvanced7m
Production
9 topics- File UploadsAdvanced7m
- CachingAdvanced6m
- Exception HandlingAdvanced7m
- Unit TestingAdvanced7m
- Performance OptimizationAdvanced7m
- SecurityAdvanced7m
- IIS DeploymentAdvanced6m
- Docker DeploymentAdvanced6m
- Complete E-Commerce ProjectAdvanced13m
Visual guides
2 diagramsCode example
A taste of the track, from Introduction to ASP.NET Core MVC.
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders(); // keep the demo output short
builder.Services.AddControllersWithViews(); // MVC = controllers + Razor views
var app = builder.Build();
app.MapDefaultControllerRoute(); // {controller=Home}/{action=Index}/{id?}
app.Urls.Add("http://127.0.0.1:5101");
await app.StartAsync();
// Act like a browser: ask for the home page and print what comes back
using var http = new HttpClient { BaseAddress = new Uri("http://127.0.0.1:5101") };
var response = await http.GetAsync("/");
Console.WriteLine(quot;{(int)response.StatusCode} {response.Content.Headers.ContentType}");
Console.WriteLine((await response.Content.ReadAsStringAsync()).Trim());
await app.StopAsync();
// Models/StoreSummary.cs
public record StoreSummary(string StoreName, int ProductCount);
// Controllers/HomeController.cs
using Microsoft.AspNetCore.Mvc;
public class HomeController : Controller
{
public IActionResult Index()
{
var model = new StoreSummary("ShopSmart", 3); // the Model
return View(model); // the View: Views/Home/Index.cshtml
}
}
@* Views/Home/Index.cshtml *@
@model StoreSummary
<h1>Welcome to @Model.StoreName</h1>
<p>@Model.ProductCount products in stock</p>
200 text/html; charset=utf-8 <h1>Welcome to ShopSmart</h1> <p>3 products in stock</p>
Practice exercises
Add an About action to HomeController that passes the text "Since 2026" to a view Views/Home/About.cshtml, which shows it in an <h2>.
Add an IExceptionFilter called LogErrorsFilter that writes “Error in <action>: <message>” to the console when an action throws, and register it globally.
Create the ShopSmart project, add a .gitignore, add the EF Core SQL Server package, and run it with hot reload.
Move the ShopSmart service registrations into an extension method builder.Services.AddShopServices() in a file Extensions/ServiceCollectionExtensions.cs, and call it from Program.cs.
Write a CorrelationIdMiddleware class that reads the X-Correlation-Id request header (or creates a new GUID), stores it in context.Items["CorrelationId"], and adds it to the response headers.
Add a UseWhen branch that, for paths starting with /api, writes “API call: <method> <path>” to the console before continuing.
Show all 42 exercises
Add a route "blog/{year:int}/{month:int}/{slug}" handled by BlogController.Post(int year, int month, string slug), which returns the three values as text.
Add a Search(string q) action to ProductsController that returns the matching products (name contains q, case-insensitive) to the Index view, or redirects to Index when q is empty.
Add an action Export() that returns all product names as a text file products.txt, one per line.
Change the view so that items with a price above 1000 get the CSS class "premium" (and items in stock still have no class), and show the total number of items at the bottom.
Add an optional section "Styles" to the layout’s <head>, and use it in the home page to add <link rel="stylesheet" href="/css/deals.css" />.
Write a CategoryMenuViewComponent that receives a list of category names from an ICategoryService and renders them as <nav><a>…</a></nav>.
Write an action Filter(ProductFilter filter) for GET /Search/Filter?Category=audio&MinPrice=500&Brands=sony&Brands=jbl where ProductFilter has Category, MinPrice (decimal?) and Brands (List<string>). Return the filter as JSON.
Add a ConfirmEmail field that must match Email, and a form-level error “Registrations are closed on Sundays” when DateTime.Today is a Sunday (shown with asp-validation-summary="ModelOnly").
Write a [MaxWords(n)] attribute that fails when a string has more than n words, and use it on a review Title with n = 8.
Register an IEmailSender implementation called ConsoleEmailSender as transient and inject it into an AccountController whose Welcome(string to) action sends “Welcome to ShopSmart!”.
Create PaymentOptions (Provider required, TimeoutSeconds between 5 and 60) bound from a "Payment" section with startup validation, and inject IOptions<PaymentOptions> into a CheckoutController that returns the provider name.
Add an "Email" section with SmtpHost, Port and From to appsettings.json, bind it to EmailSettings with builder.Services.Configure<EmailSettings>(…), and print Port from IOptions<EmailSettings>.
In a layout, load /lib/site.js in Development and https://cdn.shopsmart.example/site.min.js everywhere else, using the environment tag helper.
Add an appsettings.json Logging section that writes Debug logs for CheckoutService, Warning for Microsoft.AspNetCore, and Information for everything else.
Write a query that returns each category name with its number of products and the average price, ordered by name.
Add a DeleteAsync(int id) method that returns true when a product was deleted.
Use AddDbContextPool instead of AddDbContext for better performance, with a pool size of 128.
Add a DisplayName property (“Name (Category)”) to the scaffolded Product without touching the generated file.
Add an Order entity with Id, OrderNumber (unique, max 20 chars), Total (precision 12,2) and PlacedAt (default SYSUTCDATETIME()), configured in an OrderConfiguration class.
Write a migration by hand that renames the Products column Name to Title without losing data, with a Down method that reverses it.
Add a Details(int id) action and view that show the product name and price, returning 404 for unknown ids.
Add GetByNameAsync(string text) to IProductRepository (name contains text, case-insensitive in the fake) and implement it in both classes.
Write a CheckoutController.Buy(int productId, int quantity) action that calls OrderService and returns View("Confirmation", result) on success or puts result.Error in TempData and redirects to the product page on failure.
Add an AccessDeniedPath "/Account/Denied" and an action that shows “You do not have access to this page.”, then protect an AdminController with [Authorize(Roles = "Admin")].
Seed an admin account at startup: create the Admin role if missing, create admin@shopsmart.example if missing, and add it to the role.
Make every page require a signed-in user by default with a fallback policy, and allow anonymous access to HomeController.Index.
Add a Remove(int id) action to CartController that decreases the quantity, removes the line at zero, and returns the remaining item count.
Add a Download(string name) action that returns an uploaded file only if name matches the pattern of 32 hex characters plus .png, preventing path traversal.
Output-cache a product page /Products/Details/{id} for 2 minutes, varying by the id route value, in a policy named "Product" tagged "products".
Write an IExceptionHandler that handles OperationCanceledException (the user closed the page) by setting status 499 and returning true, so it is not logged as an error.
Write a test that checks Details does not call the repository more than once and returns a ViewResult whose ViewName is null (the default view).
Enable response compression for HTTPS responses with Brotli and Gzip.
Configure Content-Security-Policy-Report-Only instead of the enforced header, with a report-uri of /csp-reports, and add an endpoint that logs posted reports.
Write the PowerShell steps that deploy a new version with zero file-lock errors: create app_offline.htm, copy the publish folder, remove app_offline.htm.
Write a docker-compose.yml that runs ShopSmart (built from the Dockerfile) and SQL Server 2022, passes the connection string to the app, and starts the app after the database is healthy.
Make OrderService reject an order when a product in the cart no longer exists (deleted), returning “Some items are no longer available.”.
Common interview questions
- What is Program.cs responsible for in ASP.NET Core?
- What is the difference between IActionResult types like View, Json, Redirect and NotFound?
- What is ASP.NET Core MVC?
- What is Kestrel?
- How does conventional routing work?
- What are tag helpers?
- What is _ViewImports.cshtml for?
- Explain transient, scoped and singleton lifetimes.
- Why must UseAuthentication come before UseAuthorization?
- How does configuration work in ASP.NET Core?
- What are view components?
- Code-first vs database-first with EF Core?
- What is the repository pattern, and do you need it with EF Core?
- What is the request pipeline?
- Where do model binding values come from?
- How do environments work in ASP.NET Core?
- What is the options pattern?
- How does logging work in ASP.NET Core?
- What does a migration contain, and how do you apply it?
- What does a service layer add?
- How do you handle file uploads safely?
- How do policy-based authorization and claims work?
- What caching options does ASP.NET Core offer?
- What does ASP.NET Core Identity provide?
- How do you unit-test a controller?
- How do you speed up an ASP.NET Core MVC site?
- How do you containerise an ASP.NET Core app?