LEARN BUILD GROW TOGETHER
Practical knowledge for developers
DEVELOPER LEARNING HUB
Learn. Build. Grow Together.

Practical tutorials, real-world examples and interview preparation.

.NETC#SQL SERVERANGULAR
Showing posts with label Postman. Show all posts

Build Your First .NET Core Web API Using C# – Step-by-Step Practical Guide

 

Introduction

In the previous articles, we explored the fundamentals of .NET Core Web API, HTTP methods, routing, and the difference between Minimal APIs and Controllers.

Now it's time to put that knowledge into practice.

In this article, we'll create an Employee Management Web API from scratch using C# and .NET 8.

We'll build an API that allows users to:

  • Retrieve all employees.

  • Retrieve an employee by ID.

  • Add a new employee.

  • Update employee information.

  • Delete an employee.

We'll also understand the project structure, configure the application, create a controller, implement endpoints, and test everything using Postman.

By the end of this tutorial, you'll have a basic working Web API that you can run on your local machine.

1. Prerequisites

Before starting, make sure you have the following tools installed:

ToolPurpose
.NET 8 SDKBuild and run the Web API
Visual Studio 2022 or laterDevelopment environment
C#Programming language
PostmanTest HTTP requests

You can also use Visual Studio Code with the .NET SDK.

To check whether the .NET SDK is installed, open Command Prompt or a terminal and execute:

dotnet --version

You should see an installed SDK version. For this tutorial, use a .NET 8 SDK.

You can verify the installed SDKs using:

dotnet --list-sdks

2. Create a new .NET Core Web API project

There are two convenient ways to create a Web API project.

Option A: Using Visual Studio

  1. Open Visual Studio.

  2. Select Create a new project.

  3. Search for ASP.NET Core Web API.

  4. Select the Web API template.

  5. Click Next.

  6. Enter the project name: EmployeeManagementAPI.

  7. Select the project location.

  8. Click Next.

  9. Choose .NET 8.0 as the framework.

  10. Select the Controller-based option if the wizard offers it.

  11. Click Create.

For this tutorial, we'll use Controllers rather than Minimal APIs.

Option B: Using the .NET CLI

You can also create the project directly from the terminal.

Execute:

dotnet new webapi --use-controllers -n EmployeeManagementAPI

Move into the project directory:

cd EmployeeManagementAPI

Restore the project dependencies:

dotnet restore

Build the application:

dotnet build

If the build completes successfully, your project is ready for development.

3. Understand the project structure

After creating the project, you'll see a structure similar to this:

EmployeeManagementAPI
│
├── Controllers
│   └── WeatherForecastController.cs
│
├── Properties
│   └── launchSettings.json
│
├── appsettings.json
├── appsettings.Development.json
├── EmployeeManagementAPI.csproj
└── Program.cs

Let's understand the important files.

Controllers

This folder contains controller classes that handle incoming HTTP requests.

For example, we'll create:

Controllers
└── EmployeesController.cs

Program.cs

This file contains application startup configuration, service registration, middleware, and endpoint mapping.

appsettings.json

This file contains application configuration settings, such as connection strings and logging configuration.

launchSettings.json

This file contains development launch profiles, including local application URLs and environment settings.

For this tutorial, we'll keep the project simple and focus on the files needed to build our first API.

4. Create the Employee model

A model represents the data structure used by our application.

In our Employee Management application, every employee will contain:

  • Employee ID

  • Employee Name

  • Department

  • Email Address

Create a folder named Models.

Inside it, create a file named Employee.cs.

Project structure:

EmployeeManagementAPI
│
├── Controllers
├── Models
│   └── Employee.cs
│
└── Program.cs

Add the following code:

namespace EmployeeManagementAPI.Models;

public class Employee
{
    public int Id { get; set; }

    public string Name { get; set; } = string.Empty;

    public string Department { get; set; } = string.Empty;

    public string Email { get; set; } = string.Empty;
}

Let's understand the properties.

PropertyData typePurpose
IdintUnique employee identifier
NamestringEmployee name
DepartmentstringEmployee department
EmailstringEmployee email address

We'll use this model to represent employee information in our API.

In a later article, we'll introduce DTOs to separate API request and response models from application entities.

5. Configure Program.cs

Now open Program.cs.

This is the entry point of our application.

Replace its contents with:

var builder = WebApplication.CreateBuilder(args);

// Register controller services
builder.Services.AddControllers();

var app = builder.Build();

// Configure middleware
if (app.Environment.IsDevelopment())
{
    // Development-specific configuration can go here
}

app.UseHttpsRedirection();

// Map controller endpoints
app.MapControllers();

app.Run();

Let's understand the important statements.

1. Create the builder

var builder = WebApplication.CreateBuilder(args);

This creates the application builder and loads the default application configuration.

2. Register controllers

builder.Services.AddControllers();

This registers the services required for controller-based API development.

3. Build the application

var app = builder.Build();

This builds the application using the registered services and configuration.

4. Enable HTTPS redirection

app.UseHttpsRedirection();

This middleware redirects HTTP requests to HTTPS when the application has an appropriate HTTPS endpoint configured.

5. Map controller endpoints

app.MapControllers();

This makes attribute-routed controller endpoints available to the application's routing system.

6. Run the application

app.Run();

This starts the web application and begins accepting requests.

Our basic application configuration is now ready.

6. Create the EmployeesController

Now we'll create the main controller that handles employee-related operations.

Inside the Controllers folder, create:

EmployeesController.cs

Add the following code:

using Microsoft.AspNetCore.Mvc;
using EmployeeManagementAPI.Models;

namespace EmployeeManagementAPI.Controllers;

[ApiController]
[Route("api/[controller]")]
public class EmployeesController : ControllerBase
{
    private static readonly List<Employee> Employees =
    [
        new Employee
        {
            Id = 101,
            Name = "Rahul",
            Department = "IT",
            Email = "rahul@example.com"
        },
        new Employee
        {
            Id = 102,
            Name = "Priya",
            Department = "HR",
            Email = "priya@example.com"
        },
        new Employee
        {
            Id = 103,
            Name = "Amit",
            Department = "Finance",
            Email = "amit@example.com"
        }
    ];

    private static int _nextId = 104;

    // GET: api/employees
    [HttpGet]
    public IActionResult GetEmployees()
    {
        return Ok(Employees);
    }

    // GET: api/employees/101
    [HttpGet("{id:int}")]
    public IActionResult GetEmployeeById(int id)
    {
        var employee = Employees.FirstOrDefault(x => x.Id == id);

        if (employee is null)
        {
            return NotFound(new
            {
                Message = "Employee not found."
            });
        }

        return Ok(employee);
    }

    // POST: api/employees
    [HttpPost]
    public IActionResult CreateEmployee(Employee employee)
    {
        employee.Id = _nextId++;

        Employees.Add(employee);

        return CreatedAtAction(
            nameof(GetEmployeeById),
            new { id = employee.Id },
            employee);
    }

    // PUT: api/employees/101
    [HttpPut("{id:int}")]
    public IActionResult UpdateEmployee(
        int id,
        Employee updatedEmployee)
    {
        var employee = Employees.FirstOrDefault(x => x.Id == id);

        if (employee is null)
        {
            return NotFound(new
            {
                Message = "Employee not found."
            });
        }

        employee.Name = updatedEmployee.Name;
        employee.Department = updatedEmployee.Department;
        employee.Email = updatedEmployee.Email;

        return Ok(employee);
    }

    // DELETE: api/employees/101
    [HttpDelete("{id:int}")]
    public IActionResult DeleteEmployee(int id)
    {
        var employee = Employees.FirstOrDefault(x => x.Id == id);

        if (employee is null)
        {
            return NotFound(new
            {
                Message = "Employee not found."
            });
        }

        Employees.Remove(employee);

        return NoContent();
    }
}

Now let's understand how each API endpoint works.

7. Understand the API endpoints

We have created five endpoints using different HTTP methods.

A. GET – Retrieve all employees

[HttpGet]
public IActionResult GetEmployees()
{
    return Ok(Employees);
}

This endpoint retrieves all employees from the collection.

Request:

GET /api/employees

Expected status:

200 OK

Response:

[
  {
    "id": 101,
    "name": "Rahul",
    "department": "IT",
    "email": "rahul@example.com"
  },
  {
    "id": 102,
    "name": "Priya",
    "department": "HR",
    "email": "priya@example.com"
  },
  {
    "id": 103,
    "name": "Amit",
    "department": "Finance",
    "email": "amit@example.com"
  }
]

The Ok() method returns an HTTP 200 response containing the employee collection.

B. GET – Retrieve an employee by ID

[HttpGet("{id:int}")]
public IActionResult GetEmployeeById(int id)
{
    var employee = Employees.FirstOrDefault(x => x.Id == id);

    if (employee is null)
    {
        return NotFound();
    }

    return Ok(employee);
}

This endpoint retrieves an individual employee using their ID.

Request:

GET /api/employees/101

Expected response:

{
  "id": 101,
  "name": "Rahul",
  "department": "IT",
  "email": "rahul@example.com"
}

If the employee does not exist, the API returns:

404 Not Found

C. POST – Create a new employee

[HttpPost]
public IActionResult CreateEmployee(Employee employee)
{
    employee.Id = _nextId++;

    Employees.Add(employee);

    return CreatedAtAction(
        nameof(GetEmployeeById),
        new { id = employee.Id },
        employee);
}

This endpoint creates a new employee.

Request:

POST /api/employees

Request body:

{
  "name": "Neha",
  "department": "Marketing",
  "email": "neha@example.com"
}

The API assigns a new ID and adds the employee to the collection.

Expected status:

201 Created

Example response:

{
  "id": 104,
  "name": "Neha",
  "department": "Marketing",
  "email": "neha@example.com"
}

CreatedAtAction() returns a 201 response and identifies the location of the newly created employee.

D. PUT – Update an existing employee

[HttpPut("{id:int}")]
public IActionResult UpdateEmployee(
    int id,
    Employee updatedEmployee)
{
    var employee = Employees.FirstOrDefault(x => x.Id == id);

    if (employee is null)
    {
        return NotFound();
    }

    employee.Name = updatedEmployee.Name;
    employee.Department = updatedEmployee.Department;
    employee.Email = updatedEmployee.Email;

    return Ok(employee);
}

This endpoint updates an existing employee.

Request:

PUT /api/employees/101

Request body:

{
  "name": "Rahul Sharma",
  "department": "Engineering",
  "email": "rahul.sharma@example.com"
}

Expected response:

{
  "id": 101,
  "name": "Rahul Sharma",
  "department": "Engineering",
  "email": "rahul.sharma@example.com"
}

The ID comes from the URL. The remaining fields are taken from the request body.

E. DELETE – Remove an employee

[HttpDelete("{id:int}")]
public IActionResult DeleteEmployee(int id)
{
    var employee = Employees.FirstOrDefault(x => x.Id == id);

    if (employee is null)
    {
        return NotFound();
    }

    Employees.Remove(employee);

    return NoContent();
}

This endpoint removes an employee from the collection.

Request:

DELETE /api/employees/101

Expected status:

204 No Content

A 204 response indicates that the operation succeeded and the server has no response body to return.

8. Run your first Web API

Now that we have created the model, controller, and application configuration, let's run the project.

Open the terminal inside your project directory and execute:

dotnet run

You should see output indicating that the application is listening on a local address.

For example:

Now listening on: https://localhost:7001
Now listening on: http://localhost:5001
Application started.

These ports are examples. Your application may use different ports depending on its launch settings.

Copy the HTTPS URL displayed in your terminal.

For example:

https://localhost:7001

Your employee API base URL will be:

https://localhost:7001/api/employees

Your first Web API is now running.

9. Test the API using Postman

Postman allows you to send HTTP requests and inspect API responses without building a frontend application.

Let's test each endpoint.

Test 1: Retrieve all employees

  • Method: GET

  • URL: https://localhost:7001/api/employees

Click Send.

You should receive a 200 OK response containing all employees.

Test 2: Retrieve an employee by ID

  • Method: GET

  • URL: https://localhost:7001/api/employees/101

Expected result: Employee Rahul.

Test 3: Create a new employee

  • Method: POST

  • URL: https://localhost:7001/api/employees

  • Select Body → raw → JSON.

Request body:

{
  "name": "Neha",
  "department": "Marketing",
  "email": "neha@example.com"
}

Click Send.

Expected result: 201 Created.

Test 4: Update an employee

  • Method: PUT

  • URL: https://localhost:7001/api/employees/101

  • Select Body → raw → JSON.

Request body:

{
  "name": "Rahul Sharma",
  "department": "Engineering",
  "email": "rahul.sharma@example.com"
}

Expected result: 200 OK.

Test 5: Delete an employee

  • Method: DELETE

  • URL: https://localhost:7001/api/employees/101

Expected result: 204 No Content.

After deletion, send the GET request again:

GET /api/employees/101

You should receive:

404 Not Found

This confirms that the employee was removed from the in-memory collection.

10. Understand the complete project structure

After completing the implementation, your project should look like this:

EmployeeManagementAPI
│
├── Controllers
│   └── EmployeesController.cs
│
├── Models
│   └── Employee.cs
│
├── Properties
│   └── launchSettings.json
│
├── appsettings.json
├── appsettings.Development.json
├── EmployeeManagementAPI.csproj
└── Program.cs

Let's understand the request flow:

Postman / Client Application
          |
          v
   HTTP Request
          |
          v
       Kestrel
          |
          v
     Middleware
          |
          v
       Routing
          |
          v
EmployeesController
          |
          v
   Employee Collection
          |
          v
    HTTP Response
          |
          v
Postman / Client Application

This connects the concepts we learned in Days 1 and 2 with the practical implementation.

11. Important limitations of this example

Our first API uses an in-memory collection to keep the implementation beginner-friendly.

However, there are some limitations you should understand.

1. Data is not permanent

The employee records exist only while the application is running. Restarting the application resets the collection to its initial values.

2. No SQL Server integration

We are not using a database yet. Database connectivity will be introduced in the upcoming Week 2 articles.

3. No separate service layer

For simplicity, the controller directly handles the collection operations. In a larger application, business logic should be moved into appropriate services.

4. No DTOs

We are using the Employee model directly for request and response data. Later, we'll understand why DTOs are important for separating API contracts from internal application models.

5. Not production-ready storage

A static in-memory list is not suitable for a multi-user production application. It is not persistent or designed for concurrent data modification.

The purpose of this tutorial is to understand the basic structure and working of a controller-based Web API before adding more advanced architecture.

12. Common mistakes beginners should avoid

1. Forgetting AddControllers()

If you are using controllers, register them in the service container:

builder.Services.AddControllers();

2. Forgetting MapControllers()

Without mapping controller endpoints, the application will not expose the controller routes:

app.MapControllers();

3. Using the wrong API URL

Check the actual port displayed when your application starts.

4. Sending invalid JSON

When using Postman, select Body → raw → JSON and provide valid JSON.

5. Using the wrong HTTP method

A GET endpoint cannot be called using POST unless an endpoint supporting POST has also been defined.

6. Expecting data to survive an application restart

Our example uses an in-memory collection. It is not connected to SQL Server.

13. Interview questions

Q1. How do you create a Web API project in .NET 8?

You can create a controller-based Web API using the Visual Studio Web API template or the CLI command:

dotnet new webapi --use-controllers -n EmployeeManagementAPI

Q2. What is the purpose of Program.cs?

Program.cs is the application's entry point. It is used to configure services, middleware, application settings, and endpoint mapping.

Q3. What is the purpose of AddControllers()?

It registers the services required for controller-based API development.

Q4. What is the purpose of MapControllers()?

It maps attribute-routed controller endpoints so incoming requests can reach the appropriate controller actions.

Q5. What is ControllerBase?

ControllerBase is a base class that provides functionality commonly used by API controllers, such as returning HTTP responses.

Q6. What is IActionResult?

IActionResult represents an HTTP action result. It allows a controller action to return different response types, such as 200 OK, 201 Created, 400 Bad Request, and 404 Not Found.

Q7. What is the difference between Ok() and CreatedAtAction()?

Ok() returns an HTTP 200 response, while CreatedAtAction() returns an HTTP 201 response and identifies the newly created resource.

Q8. Why do we use [ApiController]?

It enables API-specific conventions, including automatic model validation responses for invalid models in supported scenarios, binding-source inference, and other API behaviors.

Q9. Why is an in-memory collection not suitable for production?

It does not provide permanent storage, is not shared across multiple application instances, and requires appropriate concurrency handling. Production applications generally use persistent storage such as SQL Server.

Q10. What is the difference between a Web API and a frontend application?

A frontend application provides the user interface and sends requests, while a Web API handles backend operations and returns data or HTTP responses.

Conclusion

Congratulations! You have now built your first controller-based .NET Core Web API using C# and .NET 8.

In this tutorial, we:

  • Created a new Web API project.

  • Understood the project structure.

  • Created an Employee model.

  • Configured Program.cs.

  • Created an EmployeesController.

  • Implemented GET, POST, PUT, and DELETE endpoints.

  • Ran the API locally.

  • Tested the endpoints using Postman.

You have now moved from understanding Web API concepts to implementing a working application.

The next step is to understand how the client and server exchange structured data.

What's next?

In Day 7, we'll explore Understanding Request and Response with JSON.

We'll understand request headers, request bodies, response bodies, content types, JSON serialization, deserialization, and how data travels between an Angular application and a .NET Core Web API.


Skills Tutorials – Learn • Build • Grow Together

Continue learning with our 30-day .NET Core Web API series.