Back to Articles

Posted on: November 8 2025
aspnet-core
webapi
csharp
postgresql
vscode

In this guide, we'll build a simple ASP.NET Core Web API with a controller, connected to a PostgreSQL database — all using Visual Studio Code.


🧰 Prerequisites

Make sure you have the following installed:


🚀 Create a New API Project

Open your terminal and run:

dotnet new webapi --use-controllers -o TodoApi
cd TodoApi
code -r .

This creates a new ASP.NET Core Web API project and opens it in VS Code.


🧩 Add Swagger for API Docs

Add the NSwag.AspNetCore package to enable OpenAPI (Swagger UI):

dotnet add package NSwag.AspNetCore

Then, open Program.cs and update it like this:

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.UseSwaggerUi(options =>
    {
        options.DocumentPath = "/openapi/v1.json";
    });
}

Now when you run the app, you’ll have an interactive API UI at: 👉 https://localhost:5001/swagger


🧱 Create the Model

Create a folder named Models, and inside it, add TodoItem.cs:

namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

This class represents a single "to-do" item in your database.


🗄️ Add Entity Framework Core

Entity Framework Core (EF Core) lets us interact with a database using C# models.

Install EF Core:

dotnet add package Microsoft.EntityFrameworkCore --version 9.0.10

We’ll use PostgreSQL, so add the provider packages:

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools

🔗 Configure the Database Connection

Open appsettings.json and add your connection string:

{
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Port=5432;Database=CSharpCornerDB;Username=yourusername;Password=yourpassword"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

🧩 Create the Database Context

Add a Data folder and inside it, create TodoContext.cs:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Data;

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

    public DbSet<TodoItem> TodoItems => Set<TodoItem>();
}

Then register the context in Program.cs:

using Microsoft.EntityFrameworkCore;
using TodoApi.Data;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddDbContext<TodoContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

🧠 Create the Controller

Add a folder named Controllers and create a file called TodoItemsController.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Data;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
        => await _context.TodoItems.ToListAsync();

    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var item = await _context.TodoItems.FindAsync(id);
        if (item == null) return NotFound();
        return item;
    }

    [HttpPost]
    public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
    {
        _context.TodoItems.Add(item);
        await _context.SaveChangesAsync();
        return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
    {
        if (id != item.Id) return BadRequest();
        _context.Entry(item).State = EntityState.Modified;
        await _context.SaveChangesAsync();
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var item = await _context.TodoItems.FindAsync(id);
        if (item == null) return NotFound();

        _context.TodoItems.Remove(item);
        await _context.SaveChangesAsync();
        return NoContent();
    }
}

🧩 Apply Migrations and Update Database

Initialize EF migrations:

dotnet ef migrations add InitialCreate
dotnet ef database update

This creates the database schema in PostgreSQL.


▶️ Run the API

Finally, run the app:

dotnet run

Visit /swagger to explore and test your API endpoints.


🎉 Done!

You now have a working ASP.NET Core 9 Web API connected to PostgreSQL, with full CRUD operations and Swagger documentation — built entirely from Visual Studio Code.


Happy coding! 🧑‍💻