Creating an ASP.NET Core MVC project takes a single command, but understanding what is generated and why each piece exists transforms it from a magic scaffold into a structure you can confidently extend. The MVC template produces a working application with a home page, error handling, and static file serving โ a proper starting point rather than a blank slate. Knowing the purpose of every folder and file prevents the confusion that comes from discovering unknown pieces later.
Creating the Project
// โโ Create a new MVC project โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
dotnet new mvc -n BlogApp.Web -o src/BlogApp.Web
// โโ Generated project structure โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// BlogApp.Web/
// โโโ Controllers/
// โ โโโ HomeController.cs โ default controller (Index, Privacy, Error)
// โโโ Models/
// โ โโโ ErrorViewModel.cs โ view model for error page
// โโโ Views/
// โ โโโ Home/
// โ โ โโโ Index.cshtml โ home page view
// โ โ โโโ Privacy.cshtml
// โ โโโ Shared/
// โ โ โโโ _Layout.cshtml โ master layout template
// โ โ โโโ _ValidationScriptsPartial.cshtml
// โ โ โโโ Error.cshtml
// โ โโโ _ViewImports.cshtml โ global using directives for views
// โ โโโ _ViewStart.cshtml โ sets default layout for all views
// โโโ wwwroot/
// โ โโโ css/ โ site CSS (site.css)
// โ โโโ js/ โ site JavaScript (site.js)
// โ โโโ lib/ โ client-side libraries (Bootstrap, jQuery)
// โ โโโ favicon.ico
// โโโ appsettings.json
// โโโ Program.cs
_ViewImports.cshtml file adds global directives to all views โ @using BlogApp.Web.Models, @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers. Tag Helpers (the asp-for, asp-action, asp-controller attributes) are registered here. Without addTagHelper, Tag Helpers do not work in any view. The underscore prefix on _ViewImports.cshtml, _ViewStart.cshtml, _Layout.cshtml, and partial views is a convention that marks these files as non-renderable directly โ they support other views but are not endpoints themselves._ViewStart.cshtml file sets the default layout for all views: @{ Layout = "_Layout"; }. Every view that does not explicitly set Layout = null (or override with a different layout) will be wrapped in _Layout.cshtml. This is why adding the navigation bar, footer, and common scripts to _Layout.cshtml makes them appear on every page without touching individual views. Override the layout in a specific view with @{ Layout = "_AdminLayout"; } or @{ Layout = null; } for pages that do not need the standard shell.wwwroot folder is the only folder served as static content by UseStaticFiles(). Files outside wwwroot (including appsettings.json, source code, and view files) are never accessible directly via HTTP. Never put files in wwwroot that should not be publicly downloadable โ no configuration files, no connection strings, no private keys. The wwwroot folder is the web root; everything in it is public.Program.cs for MVC
// โโ MVC Program.cs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
var builder = WebApplication.CreateBuilder(args);
// AddControllersWithViews โ registers MVC with Razor view engine
// (vs AddControllers for Web API โ no view engine, no Razor)
builder.Services.AddControllersWithViews();
// Register application services
builder.Services.AddScoped<IPostService, PostService>();
builder.Services.AddDbContext<AppDbContext>(opts =>
opts.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
var app = builder.Build();
// โโ Middleware pipeline for MVC โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); // serve from wwwroot โ BEFORE routing
app.UseRouting();
app.UseAuthorization();
// Conventional routing โ the MVC default route
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Common Mistakes
Mistake 1 โ Using AddControllers instead of AddControllersWithViews
โ Wrong โ Razor view engine not registered; View() returns an error:
builder.Services.AddControllers(); // no Razor โ views cannot render!
โ
Correct โ use AddControllersWithViews() for MVC applications.
Mistake 2 โ Not calling UseStaticFiles before UseRouting
โ Wrong โ static files (CSS, JS) go through the routing pipeline unnecessarily, adding overhead.
โ Correct โ UseStaticFiles before UseRouting; static files short-circuit before routing.