Skip to main content

How to Build a REST API with ASP.NET Core 8 (Tutorial)

Learn how to build a REST API with ASP.NET Core 8 step by step. Full C# code, CRUD, EF Core, and best practices. Start building your Web API today!

Want to build a REST API with ASP.NET Core? You're in the right place. In this step-by-step C# REST API tutorial, you'll create a fully working ASP.NET Core 8 Web API from scratch — complete with CRUD endpoints, Entity Framework Core, dependency injection, and the best practices senior .NET developers use in production. By the end, you'll have a runnable API and a clear understanding of why each piece matters, not just how to wire it up.

ASP.NET Core 8 is one of the fastest web frameworks available today, and its minimal API model makes spinning up endpoints faster than ever. Whether you're a beginner searching "how to create a Web API in .NET 8" or an intermediate developer looking for best practices, this guide has you covered.

What You'll Need to Build a REST API with ASP.NET Core 8

Before we write any code, make sure you have the following installed:

  • .NET 8 SDK — download from the official Microsoft site.
  • An IDE — Visual Studio 2022, VS Code, or JetBrains Rider.
  • Basic knowledge of C# and HTTP verbs (GET, POST, PUT, DELETE).

Verify your installation by running this command in your terminal:

dotnet --version
# Should output 8.x.x

Step 1: Create the ASP.NET Core 8 Web API Project

Open your terminal and scaffold a new Web API project. The webapi template gives you a ready-to-run starting point with Swagger/OpenAPI support already configured.

dotnet new webapi -n ProductApi
cd ProductApi
dotnet run

This generates a project and launches it on a local port (e.g. https://localhost:7090). Navigate to /swagger in your browser and you'll see interactive API documentation out of the box. That's the power of ASP.NET Core 8 — a working API in under a minute.

Step 2: Define Your Model

Every REST API revolves around resources. Our resource is a Product. Create a new file Models/Product.cs. We use a model class to give EF Core and the serializer a strongly-typed shape to work with.

namespace ProductApi.Models;

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int Stock { get; set; }
}

Why: Initializing Name to string.Empty avoids nullable reference warnings, which are enabled by default in .NET 8. This small habit prevents a whole class of NullReferenceException bugs.

Step 3: Set Up Entity Framework Core for CRUD

To persist data, we'll use Entity Framework Core CRUD with an in-memory database for this tutorial (swap it for SQL Server or PostgreSQL in production). Install the required packages:

dotnet add package Microsoft.EntityFrameworkCore.InMemory

Create a database context at Data/AppDbContext.cs. The DbContext is the bridge between your C# objects and the database.

using Microsoft.EntityFrameworkCore;
using ProductApi.Models;

namespace ProductApi.Data;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options) { }

    public DbSet<Product> Products => Set<Product>();
}

Step 4: Register Services with Dependency Injection

ASP.NET Core has dependency injection (DI) built in. Open Program.cs and register your DbContext. DI lets the framework manage object lifetimes for you — a core reason ASP.NET Core apps stay testable and maintainable.

using Microsoft.EntityFrameworkCore;
using ProductApi.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseInMemoryDatabase("ProductsDb"));

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

Step 5: Build the CRUD Endpoints (Minimal API)

Now the heart of the tutorial. The minimal API ASP.NET Core approach lets you map HTTP routes directly to handler functions — clean, fast, and ideal for microservices. Add these endpoints to Program.cs before app.Run():

using ProductApi.Models;

// GET all products
app.MapGet("/api/products", async (AppDbContext db) =>
    await db.Products.ToListAsync());

// GET a single product by id
app.MapGet("/api/products/{id}", async (int id, AppDbContext db) =>
    await db.Products.FindAsync(id) is Product product
        ? Results.Ok(product)
        : Results.NotFound());

// POST create a new product
app.MapPost("/api/products", async (Product product, AppDbContext db) =>
{
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Results.Created($"/api/products/{product.Id}", product);
});

// PUT update an existing product
app.MapPut("/api/products/{id}", async (int id, Product input, AppDbContext db) =>
{
    var product = await db.Products.FindAsync(id);
    if (product is null) return Results.NotFound();

    product.Name = input.Name;
    product.Price = input.Price;
    product.Stock = input.Stock;
    await db.SaveChangesAsync();
    return Results.NoContent();
});

// DELETE a product
app.MapDelete("/api/products/{id}", async (int id, AppDbContext db) =>
{
    var product = await db.Products.FindAsync(id);
    if (product is null) return Results.NotFound();

    db.Products.Remove(product);
    await db.SaveChangesAsync();
    return Results.NoContent();
});

app.Run();

Why these status codes matter: A well-designed REST API speaks HTTP correctly. 201 Created signals a new resource and returns its location, 204 No Content confirms a successful update or delete with no body, and 404 Not Found tells clients the resource doesn't exist. Returning the right status code is the difference between an amateur and a professional Web API.

Step 6: Test Your REST API

Run the project again with dotnet run and open Swagger UI. Try creating a product with a POST request:

{
  "name": "Wireless Mouse",
  "price": 24.99,
  "stock": 150
}

You can also test from the command line with curl:

curl -X POST https://localhost:7090/api/products \
  -H "Content-Type: application/json" \
  -d '{"name":"Wireless Mouse","price":24.99,"stock":150}'

Best Practices When You Build a REST API with ASP.NET Core

Now that the API works, here's how to take it to production quality:

  • Use DTOs, not entities, in responses. Exposing EF Core entities directly leaks your database schema and risks over-posting attacks. Map to a ProductDto instead.
  • Add input validation. Use data annotations or FluentValidation so clients can't submit negative prices or empty names.
  • Implement async all the way. Every database call above uses async/await — this keeps threads free and lets your API handle thousands of concurrent requests.
  • Version your API. Prefix routes with /api/v1/ so you can evolve without breaking existing clients.
  • Return consistent error responses. Use ProblemDetails (RFC 7807), which ASP.NET Core 8 supports natively via AddProblemDetails().
  • Add pagination to list endpoints so a GET on thousands of records doesn't crush performance.

Common Pitfalls to Avoid

  • Forgetting HTTPS redirection in production — always enforce TLS.
  • Blocking calls like .Result or .Wait() on async methods, which cause deadlocks.
  • Returning 200 OK for everything — clients rely on accurate status codes.
  • Leaving Swagger enabled in production unless you intentionally want public docs.

Controllers vs. Minimal APIs: Which Should You Use?

This tutorial used minimal APIs because they're concise and perfect for small-to-medium services. For larger applications with complex routing, filters, and model binding, traditional controllers (using [ApiController] and ControllerBase) offer more structure. The good news: both are first-class citizens in ASP.NET Core 8, and you can mix them in the same project.

Conclusion: You Just Built a REST API with ASP.NET Core 8

Congratulations — you now know how to build a REST API with ASP.NET Core from an empty folder to a fully functional CRUD service. Let's recap the key takeaways:

  • Scaffold quickly with dotnet new webapi and the built-in Swagger UI.
  • Model your resources and persist them with Entity Framework Core CRUD operations.
  • Use the clean minimal API ASP.NET Core syntax to map HTTP verbs to handlers.
  • Return correct HTTP status codes — 201, 204, and 404 — to build a professional Web API.
  • Apply best practices like DTOs, async, validation, and API versioning before shipping to production.

The next step is to swap the in-memory database for SQL Server, add JWT authentication, and deploy to Azure or Docker. With these fundamentals, you have everything you need to build production-grade APIs in .NET 8. Bookmark this C# REST API tutorial and start building today!

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Send an Email via SMTP with MailKit Using .NET 6

How to Send an Email in .NET Core This tutorial show you how to send an email in .NET 6.0 using the MailKit email client library. Install MailKit via NuGet Visual Studio Package Manager Console: Install-Package MailKit How to Send an HTML Email in .NET 6.0 This code sends a simple HTML email using the Gmail SMTP service. There are instructions further below on how to use a few other popular SMTP providers - Gmail, Hotmail, Office 365. // create email message var email = new MimeMessage(); email.From.Add(MailboxAddress.Parse("from_address@example.com")); email.To.Add(MailboxAddress.Parse("to_address@example.com")); email.Subject = "Email Subject"; email.Body = new TextPart(TextFormat.Html) { Text = "<h1>Test HTML Message Body</h1>" }; // send email using var smtp = new SmtpClient(); smtp.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls); smtp.Authenticate("[Username]", "[Password]"); smtp.Se...