Build a Task Tracker API with C#
Build a REST API in C# and .NET 10 with full CRUD operations.
Introduction
30 Second Summary
Every app on your phone talks to a server behind the scenes. When you check off a to-do item, add a reminder, or delete a note, your app sends a request to a program running on a server. That program is called an API.
In this project, you will build your own Task Tracker API using C# and ASP.NET Core. Your API will let any program create, read, update, and delete tasks from a to-do list.
What You'll Build
A REST API that manages tasks in an in-memory database and responds to HTTP requests with JSON data.
By the end of this project, you'll have:
- A running ASP.NET Core Minimal API project with five HTTP endpoints for managing tasks.
- Your first C# classes with properties, connected to an Entity Framework Core in-memory database.
- A .http test file that proves every endpoint works by sending real requests from inside Visual Studio.
- Secret Mission: Add a filter endpoint that returns only incomplete tasks using LINQ.
Are there any prerequisites?
None. This guide includes setup for everything you need. You just need Visual Studio 2026 installed on your machine, which already includes the .NET 10 SDK.
Create Your First .NET Project
Every .NET application starts as a project. A project is a folder of files that Visual Studio knows how to compile and run as a single program.
In this step, you will create a new project using the ASP.NET Core Empty template and confirm it runs on your machine. This gives you a working starting point before you add any task tracking features.
In this step, get ready to:
- Create a new ASP.NET Core Empty project named TaskTracker.
- Run the project and confirm it displays "Hello World!" in your browser.
Create a new ASP.NET Core project
Visual Studio uses templates to scaffold new projects. The ASP.NET Core Empty template gives you the smallest possible web application with no extra files or configuration.
- On the Visual Studio 2026 start screen, click Create a new project.
- In the Create a new project dialog, type Empty in the search box.
- Select the ASP.NET Core Empty template from the results.
- Click Next.
- In the Project name field, type TaskTracker.
- Click Next.
- In the Additional information dialog, select .NET 10.0 (Long Term Support) from the Framework dropdown.
- Make sure the Do not use top-level statements checkbox is unchecked.
- Click Create.
Visual Studio creates your project and opens Program.cs in the editor.
What are top-level statements?
Top-level statements let you write code directly in Program.cs without wrapping it in a class or Main method. By leaving Do not use top-level statements unchecked, Visual Studio generates the simpler, modern style of C# code.
This means your entire Program.cs file reads top to bottom like a script. No ceremony, no boilerplate.
Don't see the ASP.NET Core Empty template?
Make sure you typed Empty in the search box (capital E). If you still do not see it, your Visual Studio installation may be missing the ASP.NET workload. Close the dialog, go to Tools > Get Tools and Features, check ASP.NET and web development, and install it.
Help me find the ASP.NET Core Empty template in Visual Studio 2026.
Run the project and confirm it works
Before writing any new code, confirm that the template's default app runs correctly. This catches environment issues early.
- Press Ctrl+F5 to run the app without the debugger.
- A browser window opens and displays "Hello World!" on the page.
- Close the browser tab when you have confirmed the message appears.
What does Program.cs contain?
The ASP.NET Core Empty template generated this code for you:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
- WebApplication.CreateBuilder(args) sets up the web server with default settings.
- app.MapGet("/", ...) registers a single endpoint at the root URL that returns "Hello World!".
- app.Run() starts the server and keeps it listening for requests.
In the next step, you will replace this single endpoint with a full set of task tracking endpoints.
Why is my port number different?
Visual Studio assigns a random HTTPS port between 7000 and 7300 when it creates the project. Your browser URL might show localhost:7031, localhost:7152, or any other number in that range. This is normal.
Browser did not open or no Hello World?
Make sure you pressed Ctrl+F5 (not just F5). If the browser opens but shows an error, check that you selected .NET 10.0 (Long Term Support) in the Additional information dialog when you created the project.
My project is not displaying Hello World when I run it with Ctrl+F5 in Visual Studio 2026.
✔️ Awesome, I've got everything!
Great. Double check that you see "Hello World!" in the browser, then close the browser tab.
ⓧ I'd like to double check the full code
Your Program.cs should look exactly like this:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Your project is running and your environment is confirmed. Next up, you will create your first C# class to define what a task looks like.
Create Your Task Model
Your project is up and running, confirmed by the Hello World page in your browser. Now it's time to define the data your API will work with.
Every API needs to know the shape of its data. You'll define this shape using a C# class, then connect it to a database using Entity Framework Core.
In this step, get ready to:
- Create a Todo class with properties for your task data.
- Create a database context that connects your model to Entity Framework Core.
- Install the in-memory database package.
Create the Todo class
A model class defines the structure of your data. Your task tracker needs a class that describes what a single task looks like.
- In Solution Explorer, right-click the TaskTracker project.
- Select Add, then Class.
- Name the class Todo.cs.
- Click Add.
- Define your Todo model by replacing the entire contents of Todo.cs with this code:
// Define the shape of a single task
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
What does this code do?
- public class Todo creates a new class called Todo. A class is a blueprint that defines what data a task contains.
- Id, Name, and IsComplete are properties. Each property has a type that controls what kind of value it can hold.
- string? means the Name can be empty (null). The ? is C#'s way of saying "this value might not exist."
- { get; set; } lets other code read and write each property. This is C#'s shorthand for getter and setter methods.
- Save Todo.cs by pressing Ctrl+S.
- Press Ctrl+Shift+B to build the project. The Output window at the bottom should show "Build succeeded" with 0 errors.
Build failed?
- Make sure you replaced the entire file contents, including any template code Visual Studio generated. The file should only contain the Todo class.
- Check that each property line ends with { get; set; } and a semicolon.
- Confirm the file is saved (no dot on the tab title).
Still stuck? Why is my Todo.cs not building?
✔️ Awesome, I've got everything!
Great. Make sure Todo.cs is saved before moving on.
ⓧ I'd like to double check the full code
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Create the database context class
Your model defines the shape of a task, but your API also needs a way to store and retrieve tasks. A database context is the bridge between your C# code and a database.
- In Solution Explorer, right-click the TaskTracker project.
- Select Add, then Class.
- Name the class TodoDb.cs.
- Click Add.
- Define your database context by replacing the entire contents of TodoDb.cs with this code:
using Microsoft.EntityFrameworkCore;
// Connect the Todo model to a database
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
// Expose all Todo items as a queryable collection
public DbSet<Todo> Todos => Set<Todo>();
}
What does this code do?
- DbContext is a class from Entity Framework Core that manages database connections. Your TodoDb class inherits from it to get all database features for free.
- The constructor receives configuration options (like which database to use) and passes them to the base DbContext class.
- DbSet<Todo> Todos represents the collection of all tasks in your database. You'll query, add, and delete tasks through this property.
Why an in-memory database?
A real database like SQL Server requires installation and configuration. An in-memory database behaves identically from your code's perspective, but stores data in RAM. This lets you focus on learning C# and API patterns without database setup. The code you write transfers directly to a real database later.
- Save TodoDb.cs by pressing Ctrl+S.
You'll see red underlines under DbContext and DbSet. This is expected. The next substep installs the package that provides these.
Seeing errors other than DbContext and DbSet?
- If you see a red underline on Todo (not DbContext), make sure Todo.cs exists and is saved in the same project.
- Confirm you replaced the entire contents of TodoDb.cs, including any template code Visual Studio generated.
Need a hand? Why is my TodoDb.cs showing unexpected errors?
✔️ Awesome, I've got everything!
Great. Make sure TodoDb.cs is saved before moving on.
ⓧ I'd like to double check the full code
using Microsoft.EntityFrameworkCore;
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
Install the in-memory database package
Entity Framework Core's in-memory provider is a separate package you install through NuGet, .NET's package manager.
- Click Tools in the menu bar.
- Select NuGet Package Manager, then Manage NuGet Packages for Solution.
- Click the Browse tab.
- Type Microsoft.EntityFrameworkCore.InMemory in the search box.
- Select the Microsoft.EntityFrameworkCore.InMemory package from the results.
- Check your TaskTracker project in the project list on the right.
- Click Install.
- If a license acceptance dialog appears, click I Accept.
What is NuGet?
NuGet is .NET's package manager. It downloads and installs libraries that other developers have published, so you don't have to write everything from scratch. The in-memory database package gives Entity Framework Core the ability to store data in RAM instead of requiring a full database server.
- Close the NuGet tab.
- Press Ctrl+Shift+B to build the project.
- Check the Output window at the bottom. You should see "Build succeeded" with 0 errors.
The red underlines in TodoDb.cs are now gone. Entity Framework Core recognizes DbContext and DbSet because the package is installed.
Build still failing?
- Make sure you selected the correct package. The full name is Microsoft.EntityFrameworkCore.InMemory (not Microsoft.EntityFrameworkCore alone).
- Confirm you checked the TaskTracker project checkbox before clicking Install. If the checkbox was unchecked, the package was not added to your project.
- Verify that TodoDb.cs has using Microsoft.EntityFrameworkCore; at the very top of the file.
Still stuck? Why is my project not building after installing the NuGet package?
Your data model is defined and connected to a database. Next up, you'll build the API endpoints that let you create, read, update, and delete tasks.
Build Your API Endpoints
Your data model and database context are ready. Now it's time to make your API actually do something.
Endpoints are the URLs your API listens on. Each endpoint handles a specific type of HTTP request and sends back a response. You'll define five endpoints that let any program create, read, update, and delete tasks.
In this step, get ready to:
- Register the in-memory database with dependency injection.
- Define five HTTP endpoints for CRUD operations.
- Verify the API builds and runs.
Register the database and add your first endpoints
Before your API can store tasks, it needs to know about your database. Dependency injection is how .NET connects your database to your endpoints automatically.
- In Solution Explorer, double-click Program.cs to open it.
- Select all the existing code (Ctrl+A) and delete it.
- Replace the file contents with this code:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Register the in-memory database with dependency injection
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
// GET /todoitems - return all tasks as JSON
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
// POST /todoitems - create a new task
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.Run();
What does this code do?
- using Microsoft.EntityFrameworkCore; imports the database tools you installed in the previous step.
- AddDbContext<TodoDb> registers your database context so .NET automatically provides it to any endpoint that needs it.
- UseInMemoryDatabase("TodoList") tells Entity Framework to store data in memory instead of an external database.
- MapGet defines an endpoint that responds to GET requests. It returns all tasks as a JSON array.
- MapPost defines an endpoint that responds to POST requests. It adds a task to the database and returns a 201 Created response.
What is dependency injection?
Dependency injection is a pattern where .NET creates objects (like your database) and passes them to code that needs them. Instead of each endpoint creating its own database connection, .NET creates one and shares it.
The TodoDb db parameter in each endpoint is where .NET injects the database context automatically.
- Save Program.cs by pressing Ctrl+S.
- Press Ctrl+F5 to run the app without the debugger.
- A browser opens. Add /todoitems to the end of the URL in the address bar and press Enter.
- You should see [] in the browser. This is an empty JSON array, meaning your API is working but has no tasks yet.
- Close the browser tab and press Ctrl+C in the terminal or click the red stop button in Visual Studio to stop the server.
Seeing a build error?
- Check that you installed the Microsoft.EntityFrameworkCore.InMemory NuGet package in the previous step. Without it, UseInMemoryDatabase won't be recognized.
- Make sure Todo.cs and TodoDb.cs exist in your project with the correct class names.
- Confirm you deleted the original Hello World code completely before pasting.
Help me debug my build error in Program.cs
Add the get-by-ID endpoint
Your API can list all tasks, but you also need a way to fetch a single task by its ID. This endpoint uses pattern matching to return the task if found, or a 404 response if not.
- In Program.cs, find the closing ()); of your MapGet endpoint (the line with ToListAsync());).
- Add this code below it, before the MapPost endpoint:
// GET /todoitems/{id} - return a single task or 404
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
What does this code do?
- /todoitems/{id} defines a route parameter. When someone requests /todoitems/3, .NET automatically puts 3 into the id variable.
- FindAsync(id) searches the database for a task with that ID.
- is Todo todo is C# pattern matching. It checks if the result is a Todo object (not null) and assigns it to the variable todo.
- The ? and : form a ternary expression. If found, return 200 OK with the task. If not found, return 404.
- Save Program.cs.
- You won't see a visible change yet. The next endpoints complete the file, and you'll test everything together in the next step.
Add the update and delete endpoints
The final two endpoints let you update a task's name or completion status, and remove tasks entirely. Together with the endpoints you already wrote, these complete all four CRUD operations (Create, Read, Update, Delete).
- In Program.cs, find the closing }); of your MapPost endpoint.
- Add this code below it, before app.Run();:
// PUT /todoitems/{id} - update an existing task
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
// Look up the existing task
var todo = await db.Todos.FindAsync(id);
// If no task with this ID exists, return 404
if (todo is null) return Results.NotFound();
// Update the task's properties
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
What does this code do?
- MapPut handles PUT requests, which are used to update existing resources.
- The endpoint receives both the id from the URL and a Todo inputTodo object from the request body (the new values).
- It first checks if the task exists. If not, it returns 404 immediately.
- Results.NoContent() returns a 204 status code, meaning the update succeeded but there's nothing to send back.
- Save Program.cs.
- Now add the delete endpoint directly below the MapPut closing });, still before app.Run();:
// DELETE /todoitems/{id} - remove a task
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
// Check if the task exists using pattern matching
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
What does this code do?
- MapDelete handles DELETE requests, which remove a resource.
- The if statement combines the database lookup and pattern match in one line. If the task exists, it's assigned to todo and removed.
- If no task matches the ID, the endpoint returns 404.
- Save Program.cs.
- Press Ctrl+F5 to run the app.
- A browser opens. Add /todoitems to the end of the URL and press Enter. You should see [] again. This confirms all five endpoints compiled successfully.
- Now navigate to just the base URL (remove /todoitems from the address bar). You should see a blank page. This is expected because you removed the original / route.
- Close the browser tab and stop the server in Visual Studio.
Seeing a red squiggly line or build error?
- Check for missing semicolons or closing braces }); at the end of each endpoint.
- Make sure each endpoint is placed before app.Run(); at the bottom of the file.
- Verify the using Microsoft.EntityFrameworkCore; line is at the very top of Program.cs.
Help me fix my build error after adding all five endpoints
✔️ Awesome, I've got everything!
Great. Double check you've saved Program.cs and the app ran without errors.
ⓧ I'd like to double check the full code
Here's the complete Program.cs file with all five endpoints. Make sure yours matches exactly:
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());
app.MapPost("/todoitems", async (Todo todo, TodoDb db) =>
{
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
});
app.MapPut("/todoitems/{id}", async (int id, Todo inputTodo, TodoDb db) =>
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return Results.NotFound();
todo.Name = inputTodo.Name;
todo.IsComplete = inputTodo.IsComplete;
await db.SaveChangesAsync();
return Results.NoContent();
});
app.MapDelete("/todoitems/{id}", async (int id, TodoDb db) =>
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return Results.NoContent();
}
return Results.NotFound();
});
app.Run();
Your API is fully built with all five endpoints ready to handle requests. Next up, you'll test every endpoint using Visual Studio's built-in HTTP testing tool.
Test Your API
Your API has five endpoints ready to handle requests. The code is written, but you have not actually sent any requests to it yet.
Visual Studio has a built-in HTTP testing tool that lets you send requests directly from the editor. You will use Endpoints Explorer to generate a .http file, then send requests to every endpoint and confirm they respond correctly.
In this step, get ready to:
- Send a POST request to create a task and verify a 201 response.
- Send GET requests to read all tasks and a single task by ID.
- Send PUT and DELETE requests to update and remove a task.
Generate and send a POST request
Endpoints Explorer is a tool window that shows all the endpoints your API defines. You can right-click any endpoint to generate a test request in a .http file.
- Make sure your project is still running. If you stopped it, press Ctrl+F5 to run without the debugger.
- Open Endpoints Explorer by selecting View in the top menu bar.
- Select Other Windows, then select Endpoints Explorer.
- In the Endpoints Explorer pane, right-click the POST /todoitems endpoint.
- Select Generate request.
Visual Studio creates a new file called TaskTracker.http and opens it in the editor. You will see a host address variable at the top and a basic POST request template below it.
What is the port number?
The first line of your .http file defines a variable like @TaskTracker_HostAddress = https://localhost:7031. Your port number will be different. Visual Studio assigns a random HTTPS port between 7000 and 7300 when the project is created.
This is normal. Leave whatever port Visual Studio generated for you.
- Edit the POST request so it includes a Content-Type header and a JSON body. Your POST request should look like this:
POST {{TaskTracker_HostAddress}}/todoitems
Content-Type: application/json
{
"name": "Learn C#",
"isComplete": false
}
###
What does this request do?
Content-Type: application/json tells the API that the request body is JSON. The body contains a task with a name and a completion status.
The ### at the bottom is a request separator. Everything after it belongs to a different request.
- Click the Send Request link that appears directly above the POST line.
The response appears in a pane to the right of the editor. You should see a 201 Created status and a JSON body containing your task with an id of 1.
Not seeing a response?
Make sure your project is still running. The .http file sends requests to localhost, so the app must be active to respond.
Check that there is a blank line between the Content-Type header and the JSON body. Missing this blank line is the most common syntax error in .http files.
Help me troubleshoot my .http file POST request
Send GET requests to read tasks
Now that you have created a task, you can read it back. You will add two GET requests to your .http file.
- In Endpoints Explorer, right-click the first GET /todoitems endpoint and select Generate request.
- In Endpoints Explorer, right-click the GET /todoitems/{id} endpoint and select Generate request.
- In the generated GET by ID request, replace {id} with 1 so the URL reads /todoitems/1.
Your two GET requests should look like this:
GET {{TaskTracker_HostAddress}}/todoitems
###
GET {{TaskTracker_HostAddress}}/todoitems/1
###
What is the difference between these two GET requests?
The first GET returns all tasks as a JSON array. The second GET returns a single task by its ID. If the ID does not exist, the API returns a 404 Not Found response.
- Click Send Request above the GET {{TaskTracker_HostAddress}}/todoitems line.
- Click Send Request above the GET {{TaskTracker_HostAddress}}/todoitems/1 line.
Both requests should return 200 OK. The first returns a JSON array with your task in it. The second returns the single task object.
Getting a 404 on the GET by ID?
Make sure you replaced {id} with 1 in the URL. The API uses the in-memory database, so the task you created with POST has ID 1.
Help me fix my GET request returning 404
Update and delete a task
The final two endpoints let you modify and remove tasks. You will send a PUT to mark a task as complete, then a DELETE to remove it entirely.
- In Endpoints Explorer, right-click the PUT /todoitems/{id} endpoint and select Generate request.
- Replace {id} with 1 in the generated URL.
- Edit the PUT request to include a Content-Type header and a JSON body that marks the task as complete:
PUT {{TaskTracker_HostAddress}}/todoitems/1
Content-Type: application/json
{
"id": 1,
"name": "Learn C#",
"isComplete": true
}
###
Why does PUT need the full object?
The PUT endpoint replaces all fields on the task. You send the complete updated object, not just the field you changed. Here, isComplete is now true instead of false.
- Click Send Request above the PUT line.
You should see a 204 No Content response. This means the update succeeded but there is no response body.
- In Endpoints Explorer, right-click the DELETE /todoitems/{id} endpoint and select Generate request.
- Replace {id} with 1 in the generated URL so it reads:
DELETE {{TaskTracker_HostAddress}}/todoitems/1
###
- Click Send Request above the DELETE line.
You should see another 204 No Content response. The task has been removed from the database.
- Scroll back up to the GET {{TaskTracker_HostAddress}}/todoitems request and click Send Request again.
The response should now show 200 OK with an empty JSON array []. This confirms the task was deleted.
Still seeing the task after DELETE?
Make sure the DELETE URL ends with /todoitems/1 and not /todoitems/{id}. The {id} placeholder must be replaced with the actual number.
Help me troubleshoot my DELETE request
✔️ Awesome, I've got everything!
Great. Make sure you have saved your TaskTracker.http file.
ⓧ I'd like to double check the full code
Here is the complete TaskTracker.http file. Your port number on the first line will be different.
@TaskTracker_HostAddress = https://localhost:7031
POST {{TaskTracker_HostAddress}}/todoitems
Content-Type: application/json
{
"name": "Learn C#",
"isComplete": false
}
###
GET {{TaskTracker_HostAddress}}/todoitems
###
GET {{TaskTracker_HostAddress}}/todoitems/1
###
PUT {{TaskTracker_HostAddress}}/todoitems/1
Content-Type: application/json
{
"id": 1,
"name": "Learn C#",
"isComplete": true
}
###
DELETE {{TaskTracker_HostAddress}}/todoitems/1
###
Secret mission
Add a Filter Endpoint
Your API can create, read, update, and delete tasks. But what if you only want to see tasks you haven't finished yet? Add a filter endpoint that returns only incomplete tasks using LINQ, C#'s built-in query language.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on your local machine with an in-memory database. There are no ongoing costs or cloud resources to worry about.
Decide whether to keep your project files, pause your work, or delete everything.
Resources you used:
- The TaskTracker solution and project folder (local files on your machine).
- The Microsoft.EntityFrameworkCore.InMemory NuGet package (installed inside your project folder).
- The in-memory database (automatically deleted every time you stop the app).
Keep everything running
No action needed. Choose this if you want to keep building on your Task Tracker API or experiment with more endpoints.
- Your project stays in Visual Studio 2026 and you can reopen it anytime from the start screen.
- The in-memory database resets each time you stop and restart the app, so no stale data accumulates.
Pause - I'll come back to this later
Stop the running app to free up the port and memory. Your project files stay on disk for next time.
- If your app is still running, press Shift+F5 in Visual Studio or close the browser window to stop it.
- Close the solution in Visual Studio by clicking File, then Close Solution.
- When you come back, open Visual Studio and select your TaskTracker project from the recent list on the start screen.
Delete - I don't want to use this again
Remove the project folder entirely. This deletes all source files, the NuGet packages, and the solution file.
- If your app is still running, press Shift+F5 in Visual Studio to stop it.
- Close the solution by clicking File, then Close Solution.
- Find your project folder. In Visual Studio, right-click the solution name in Solution Explorer and select Open Folder in File Explorer. Navigate up one level to the parent folder.
- Delete the TaskTracker folder. Right-click it in File Explorer and select Delete.
That's a Wrap!
That's a Wrap!
Nice work! You just built a fully functional Task Tracker API from scratch using C# and .NET 10.
You've learned how to:
- Built a complete REST API with five HTTP endpoints using ASP.NET Core Minimal APIs in Visual Studio 2026.
- Written your first C# classes with properties and nullable types, and connected them to an Entity Framework Core in-memory database.
- Tested all CRUD operations (Create, Read, Update, Delete) using Visual Studio's built-in .http file testing tool.
- Secret Mission: Added a filter endpoint using LINQ to query only incomplete tasks.
Ready to quiz yourself?