Building Your First REST API with ASP.NET Core
Minimal APIs, Entity Framework Core, and FluentValidation — a real, working ASP.NET Core API without controller-class ceremony.
Entity Framework Core migrations let you evolve your database schema through version-controlled C# code instead of manually editing tables — the .NET equivalent of Laravel's migration system, with its own specific workflow worth understanding properly.
dotnet ef migrations add CreatePostsTable
EF Core compares your current DbContext model classes against the last known database snapshot and generates a migration file describing exactly what changed:
public partial class CreatePostsTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Posts",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Title = table.Column<string>(maxLength: 255, nullable: false),
CreatedAt = table.Column<DateTime>(nullable: false),
},
constraints: table => table.PrimaryKey("PK_Posts", x => x.Id));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Posts");
}
}
The Down method is what makes a migration reversible — always verify EF Core generated a correct one, especially for anything beyond a simple add/drop column.
dotnet ef database update
This runs any migrations not yet applied to the target database, in order, tracked in a __EFMigrationsHistory table — the same role Laravel's migrations table plays.
public class Post
{
public int Id { get; set; }
[MaxLength(500)] // was 255
public string Title { get; set; }
}
dotnet ef migrations add IncreaseTitleLength
dotnet ef database update
Change the model class first, then generate the migration — EF Core diffs the model against the database, not the other way around.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category { Id = 1, Name = "General" },
new Category { Id = 2, Name = "Tutorials" }
);
}
Data configured via HasData becomes part of the migration itself — it runs exactly once, tracked the same way schema changes are, rather than needing a separate seeding script run manually.
dotnet ef database update PreviousMigrationName
Rolling back in production should always be tested against a staging copy first — a migration that DROPPED a column can't un-drop the data that was in it, regardless of how correct the Down method looks on paper.
Minimal APIs, Entity Framework Core, and FluentValidation — a real, working ASP.NET Core API without controller-class ceremony.
A complete JWT authentication setup for ASP.NET Core — issuing tokens, protecting endpoints, and role-based authorization.
Structuring an ASP.NET Core app so business logic has zero dependency on frameworks or databases — Domain, Application, Infrastructure, and Web layers.