moroz.dev

<< Back to index

How to Set Up an ASP.NET Core MVC Application with PostgreSQL

Abstract

In this article you will learn how to set up an ASP.NET Core MVC project with a PostgreSQL database using Entity Framework Core and Npgsql.

Prerequisites and Environment Setup

This walkthrough assumes you are using the JetBrains Rider IDE on a Unix-like operating system (Linux, macOS, or Windows with WSL2). To a certain extent, it may work on Windows with PowerShell, but I have not tested it.

In this workthrough, I will be using the .NET toolchain installed using mise. Ensure that mise is correctly installed and up to date:

$ mise doctor --json | jq -r .activated,.version
true
2025.7.10 linux-x64 (2025-07-14)

Install the latest .NET toolchain:

$ mise use -g dotnet
mise ~/.config/mise/config.toml tools: dotnet@9.0.301

Install and Configure PostgreSQL

Ensure that you have a recent version of PostgreSQL installed on your machine.

On Debian GNU/Linux and derivatives (Ubuntu, Linux Mint, etc.), you can install the latest version of PostgreSQL using these instructions.

On macOS, you can install PostgreSQL using Homebrew.

On Windows, you can either install PostgreSQL using an installer, or install it within WSL2 using a package for Debian GNU/Linux.

On Linux, if you have just installed PostgreSQL for the first time, you will not be able to connect to the database as a regular user:

$ psql
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "karol" does not exist

You can fix this by creating a role and a database for your user:

$ sudo su postgres -c "createuser -s $(whoami)"
$ createdb
$ psql
psql (17.5 (Debian 17.5-1.pgdg120+1))
Type "help" for help.

karol=#

Set the password for database user postgres to postgres:

$ psql -c "alter user postgres password 'postgres'"
ALTER ROLE

You should now be able to connect to PostgreSQL as user postgres, password postgres:

$ psql postgres://postgres:postgres@localhost
psql (17.5 (Debian 17.5-1.pgdg120+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql)
Type "help" for help.

postgres=#

The remaining part of this walkthrough assumes that the superuser’s username is postgres and its password is postgres.

Create Solution and Projects

Create a directory to store your projects at ~/projects:

$ mkdir -p ~/projects

In this directory, create a C# solution called MyApp:

$ cd ~/projects
$ dotnet new sln -n MyApp -o MyApp

In the solution directory, initialize a Git repository, and create an initial commit:

$ cd ~/projects/MyApp
$ git init --initial-branch=main
$ git add .
$ git commit -m "Initial commit"

Inside this solution, Create an ASP.NET MVC project called MyApp.Web using the ASP.NET Core Web App (Model-View-Controller) template. This project will contain the code related to the Web-facing functionality of the application.

$ dotnet new mvc -o MyApp.Web

Add the newly created project to the MyApp solution:

$ dotnet sln add MyApp.Web

In the project’s root directory, create a .gitignore file to avoid accidentally commiting dependencies and compiled binaries:

cat > .gitignore <<-EOF
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
EOF

Add the MyApp.Web project to Git and commit:

$ git add .
$ git commit -m "Generate MyApp.Web project"

Generate a minimal project called MyApp.Data. This is the

$ dotnet new classlib -n MyApp.Data -o MyApp.Data
$ dotnet sln add MyApp.Data

Add the MyApp.Data project to Git and commit:

$ git add .
$ git commit -m "Generate MyApp.Data project"

Install Dependencies

Within the MyApp.Data project, install a few NuGet packages related to EF Core (short for Entity Framework Core) and Npgsql (the library connecting EF Core to PostgreSQL):

$ cd ~/projects/MyApp/MyApp.Data
$ dotnet add package Microsoft.EntityFrameworkCore
$ dotnet add package Microsoft.EntityFrameworkCore.Design
$ dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL

Within the MyApp.Web project, install the same packages, as well as EFCore.NamingConventions. This library lets us configure EF Core to generate queries and migrations using snake_case for table and column names, rather than the customary PascalCase.

$ cd ~/projects/MyApp/MyApp.Web
$ dotnet add package Microsoft.EntityFrameworkCore
$ dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
$ dotnet add package Microsoft.EntityFrameworkCore.Design
$ dotnet add package EFCore.NamingConventions

Commit the changes to project dependencies:

$ git add -A
$ git commit -m "Install EF Core and Npgsql dependencies"

Install EF Core CLI

Install dotnet-ef, a command-line tool used to generate and perform database schema migrations.

$ dotnet tool install --global dotnet-ef

This command may print a message like the following:

Tools directory '/Users/karol/.dotnet/tools' is not currently on the PATH environment variable.
If you are using zsh, you can add it to your profile by running the following command:

cat << \EOF >> ~/.zprofile
# Add .NET Core SDK tools
export PATH="$PATH:/Users/karol/.dotnet/tools"
EOF

And run `zsh -l` to make it available for current session.

You can only add it to the current session by running the following command:

export PATH="$PATH:/Users/karol/.dotnet/tools"

You can invoke the tool using the following command: dotnet-ef
Tool 'dotnet-ef' (version '9.0.7') was successfully installed.

If this happens, follow the instructions printed in this message to add the newly installed command to PATH. Once this is done, dotnet-ef should be available as dotnet ef:

$ which dotnet-ef
/Users/karol/.dotnet/tools/dotnet-ef
$ dotnet ef

                     _/\__
               ---==/    \\
         ___  ___   |.    \|\
        | __|| __|  |  )   \\\
        | _| | _|   \_/ |  //|\\
        |___||_|       /   \\\/\\

Entity Framework Core .NET Command-line Tools 9.0.7

# ... omitted for brevity ...

Add Project Reference for MyApp.Data

In MyApp.Web/MyApp.Web.csproj, add a reference to the other project, MyApp.Data. This way, we can use code from that project inside MyApp.Web.

<Project Sdk="Microsoft.NET.Sdk.Web">
    <!-- ... omitted for brevity ... -->

    <!-- add this section -->
    <ItemGroup>
        <ProjectReference Include="../MyApp.Data/MyApp.Data.csproj"/>
    </ItemGroup>

</Project>

Create Directories for AppDbContext and Models

At this point, in the MyApp.Data project, there are only two source files:

$ tree --gitignore MyApp.Data
MyApp.Data
├── Class1.cs
└── MyApp.Data.csproj

1 directory, 2 files

We are not going to use Class1.cs, so delete the file:

$ cd ~/projects/MyApp/MyApp.Data
$ rm Class1.cs

Instead, create files and directories for entity classes and for AppDbContext:

$ mkdir Entities
$ touch AppDbContext.cs Entities/Member.cs

The file structure should now look like this:

$ tree --gitignore MyApp.Data
MyApp.Data
├── AppDbContext.cs
├── Entities
│   └── Member.cs
└── MyApp.Data.csproj

2 directories, 3 files

Finally, open the project in your IDE of choice.

Create AppDbContext

In MyApp.Data/AppDbContext.cs, add a class called AppDbContext. This class is going to be our main entry point for EF Core interactions.

using Microsoft.EntityFrameworkCore;

namespace MyApp.Data;

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

In MyApp.Web/Program.cs, connect your web application to AppDbContext using .AddDbContext():

using Microsoft.EntityFrameworkCore;
using MyApp.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
    options
        .UseNpgsql(builder.Configuration.GetConnectionString("AppDbContext"))
        .UseSnakeCaseNamingConvention());

// ... omitted for brevity ...