✓
Home›Tutorials›.NET & ASP.NET Core›.NET 10 Tutorial: Build Your First ASP.NET Core Minimal API
.NET & ASP.NET Core4 min read

.NET 10 Tutorial: Build Your First ASP.NET Core Minimal API

Learn how to create, run, and test your first ASP.NET Core Minimal API with .NET 10, clean HTTP responses, validation, and curl.

Welcome to the CodeWithChai ASP.NET Core 10 tutorial series. In this first lesson, you will create a small HTTP API, add two endpoints, run it locally, and test it from the command line. The goal is deliberately simple: understand the shape of a modern .NET API before adding databases, authentication, and deployment.

Prerequisites: install the .NET 10 SDK and use any editor you prefer. .NET 10 is an LTS release, and ASP.NET Core supports both Minimal APIs and controller-based APIs. We will begin with Minimal APIs because they keep a focused endpoint easy to read. Microsoft’s API overview explains when to choose each approach.

What you will build

By the end of this tutorial, your API will expose:

  • GET /api/greetings to return a small list of greetings.
  • POST /api/greetings to add a greeting after basic validation.
  • GET /health to give a simple health response during local development.

1. Create a .NET 10 project

Open a terminal in the directory where you keep projects and create an empty ASP.NET Core application. The web template is a clean start for this lesson.

dotnet new web -n Chai.Greetings.Api -f net10.0
cd Chai.Greetings.Api
dotnet run

The first run prints one or more local URLs, usually HTTPS and HTTP. Stop the app with Ctrl+C after confirming it starts.

2. Replace Program.cs with a small API

Open Program.cs and replace its contents with the following code. It uses a record for the request body, validates the input, and returns HTTP status codes that clients can understand.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var greetings = new List<Greeting>
{
    new(1, "Hello from ASP.NET Core 10"),
    new(2, "Welcome to CodeWithChai")
};

app.MapGet("/health", () => Results.Ok(new { status = "ok" }));

app.MapGet("/api/greetings", () => Results.Ok(greetings));

app.MapPost("/api/greetings", (CreateGreetingRequest request) =>
{
    var message = request.Message?.Trim();

    if (string.IsNullOrWhiteSpace(message) || message.Length > 120)
    {
        return Results.ValidationProblem(new Dictionary<string, string[]>
        {
            ["message"] = ["Message is required and must be 120 characters or fewer."]
        });
    }

    var greeting = new Greeting(greetings.Count + 1, message);
    greetings.Add(greeting);

    return Results.Created($"/api/greetings/{greeting.Id}", greeting);
});

app.Run();

public sealed record Greeting(int Id, string Message);
public sealed record CreateGreetingRequest(string? Message);

This data is intentionally stored in memory, so it disappears each time the application restarts. That is useful for learning the HTTP flow; a later lesson will replace it with a database.

3. Run and test the endpoints

Start the project again with dotnet run. Use the HTTP URL printed by the application, then test the API in a second terminal. Replace the port if your console shows a different one.

curl http://localhost:5000/health
curl http://localhost:5000/api/greetings
curl -X POST http://localhost:5000/api/greetings \
  -H "Content-Type: application/json" \
  -d '{"message":"Namaste from my first .NET API"}'
curl http://localhost:5000/api/greetings

The POST request should return 201 Created and a Location header pointing to the new resource. If you send an empty message, the API returns a validation-problem response instead.

Why this is a useful starting point

Minimal APIs are not toy APIs. They support routing, dependency injection, authentication, validation, OpenAPI, and the other building blocks you need as an application grows. Starting with a concise endpoint lets you see request binding and HTTP results without hiding them behind extra files.

For a larger team or a domain with many related actions, controller-based APIs can be a better organizational fit. The important choice is consistency: keep HTTP concerns at the edge of the application and move business rules into services as complexity grows.

Common mistakes

  • Using an unsupported SDK: run dotnet --list-sdks and confirm that a 10.x SDK is installed before creating the project.
  • Returning successful responses for invalid input: validate at the API boundary and make error responses predictable.
  • Treating the in-memory list as persistent storage: it is reset on every restart; use EF Core or another persistence layer for real data.
  • Hard-coding secrets: configuration and secret management come before deployment, not after it.

Next lesson

Next, we will add configuration, dependency injection, and a service layer so the endpoint no longer owns application logic. That will make the API easier to test and ready for a database-backed version.

Checklist

  • The project targets net10.0.
  • GET /health returns an OK response.
  • GET /api/greetings returns JSON.
  • POST /api/greetings returns 201 Created for a valid message.
  • An empty message returns a validation response.

For deeper reference material, see Microsoft’s Minimal API tutorial and the .NET 10 overview.

Continue learning

Next, learn how to configure an ASP.NET Core 10 API and use dependency injection.

See all lessons in the .NET and ASP.NET Core tutorial track.