ASP.NET Core is the modern, cross‑platform web‑development stack for the .NET ecosystem (latest LTS: .NET 8, Nov 2024). It unifies MVC, Web API and Razor Pages under a single modular runtime that runs on Windows, Linux and macOS.
github.com/dotnet/aspnetcore
Note: Legacy “ASP.NET Framework” (WebForms / MVC 5) targets Windows‑only .NET Framework 4.x. New apps should use ASP.NET Core.
// Create a Web API project targeting .NET 8 (LTS)
dotnet new webapi -n MyApi -f net8.0
// Razor Pages site
dotnet new razor -n MySite
// Minimal API
dotnet new web -n TodoMinimal
The dotnet
CLI scaffolds opinionated folders:
Folder | Purpose |
---|---|
Controllers/ | HTTP endpoints (MVC or API) |
Pages/ | Razor Pages (.cshtml) |
Data/ | Entity Framework Core DbContext & Migrations |
Program.cs | Host builder & service registration |
Program.cs
– Bootstrap & Middleware
var builder = WebApplication.CreateBuilder(args);
// 1 · Service registration
builder.Services.AddControllers(); // MVC & Web API
builder.Services.AddRazorPages(); // Razor
builder.Services.AddDbContext<AppDb>(); // Data
var app = builder.Build();
// 2 · HTTP pipeline
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Two key orchestration methods: WebApplication.CreateBuilder (configures DI, logging, config) and app.Run (starts Kestrel).
[ApiController]
[Route("api/[controller]")]
public class TodoController : ControllerBase
{
private readonly ITodoRepository _repo;
public TodoController(ITodoRepository repo) => _repo = repo;
// GET /api/todo
[HttpGet]
public IEnumerable<TodoItem> GetAll() => _repo.All();
// POST /api/todo
[HttpPost]
public ActionResult<TodoItem> Create(TodoItem dto)
{
var created = _repo.Add(dto);
return CreatedAtAction(nameof(GetById), new { id = created.Id }, created);
}
[HttpGet("{id:int}")]
public ActionResult<TodoItem> GetById(int id) =>
_repo.Find(id) is { } item ? item : NotFound();
}
Decorate methods with routing attributes such as [HttpGet], [HttpPost], and use ActionResult<T> for rich status codes.
Program.cs
("{controller=Home}/{action=Index}/{id?}"
).[Route("blog/{slug}")]
).
// id must be GUID
[HttpGet("orders/{id:guid}")]
public IActionResult Get(Guid id) { … }
// slug must match regex
[HttpGet("blog/{slug:regex(^[a-z0-9-]+$)}")]
public IActionResult Post(string slug) { … }
Razor combines C# and HTML using @
syntax:
@page
@model IndexModel
<h2>Welcome @Model.UserName!</h2>
<ul>
@foreach (var todo in Model.Todos)
{
<li>@todo.Title</li>
}
</ul>
Note: Razor Pages (~PageModel) are page‑centric; MVC Views rely on a Controller. Choose Pages for simple sites, MVC for complex domain‑driven apps.
public class TodoItem
{
public int Id { get; set; }
[Required, StringLength(80)]
public string Title { get; set; } = "";
public bool IsDone { get; set; }
}
jquery.validate
// Program.cs
builder.Services.AddScoped<ITodoRepository, TodoRepository>();
builder.Services.AddSingleton<ILoggerFactory, LoggerFactory>();
Lifetime options:
Transient
(new each request),
Scoped
(per HTTP request),
Singleton
(app wide).
// LoggingMiddleware.cs
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<LoggingMiddleware> _log;
public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> log)
=> (_next, _log) = (next, log);
public async Task InvokeAsync(HttpContext ctx)
{
_log.LogInformation("⇒ {Path}", ctx.Request.Path);
await _next(ctx);
_log.LogInformation("⇐ {Status}", ctx.Response.StatusCode);
}
}
// Register
app.UseMiddleware<LoggingMiddleware>();
public class AppDb : DbContext
{
public DbSet<TodoItem> Todos => Set<TodoItem>();
protected override void OnConfiguring(DbContextOptionsBuilder b)
=> b.UseSqlite("Data Source=todos.db");
}
dotnet ef migrations add Init
dotnet ef database update
Note: EF Core 8 brings bulk updates & improved JSON column mapping.
Scaffold with dotnet new mvc --auth Individual
for cookie auth.
builder.Services
.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", opts =>
{
opts.Authority = "https://demo.identityserver.io";
opts.Audience = "api";
});
Protect endpoints via [Authorize].
// Program.cs (no controllers)
app.MapGet("/api/todo", (ITodoRepository repo) => repo.All());
app.MapPost("/api/todo", (TodoItem dto, ITodoRepository repo) =>
{
var created = repo.Add(dto);
return Results.Created($"/api/todo/{created.Id}", created);
});
Uses route handlers and lambda‑style dependency injection for ultralight services.
Microsoft