Home > Software engineering >  Connecting to PostgreSql via Npgsql from ASP.NET Core 6 in a Docker Compose Stack
Connecting to PostgreSql via Npgsql from ASP.NET Core 6 in a Docker Compose Stack

Time:02-23

I'm trying to create a docker-compose script to fire a stack with a PostgreSql database and an ASP.NET Core 6 Web API. To test the scenario, I've created a new ASP.NET Core 6 Web API using the default template. I have then added NuGet package Npgsql (6.0.3), and a sample controller which just queries the DB engine version, e.g.:

[ApiController]
[Produces("application/json")]
public class TestController : Controller
{
    private readonly IConfiguration _config;

    public TestController(IConfiguration config)
    {
        _config = config;
    }

    [HttpGet("api/dbversion")]
    public IActionResult GetVersion()
    {
        using NpgsqlConnection conn = new(_config.GetConnectionString("Default"));

        conn.Open();

        var cmd = conn.CreateCommand();
        cmd.CommandText = "SELECT version();";

        return Ok($"Version: {cmd.ExecuteScalar() as string}");
    }
}

I then created the Docker image for this API, and written a docker-compose script as follows:

version: '3.7'

services:
  test-db:
    image: postgres
    # explicit container name
    # another approach using hostname: https://stackoverflow.com/questions/68701716/docker-compose-postgres-connection-refused
    container_name: test-db
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=postgres
    ports:
      - 5433:5432
    networks:
      - test-network

  test-api:
    image: MYREPONAME/test-api:0.0.1
    ports:
      - 5154:80
    depends_on:
      - test-db
    environment:
      - CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5433;Database=postgres
    networks:
      - test-network

networks:
  test-network:
    driver: bridge

Here I'm using the official postgres image, setting up the default credentials, redirecting the service to port 5433 in the compose stack, and consuming it from the API within the same network. I am overwriting the connection string in the script, using as host name the container name (test-db); localhost would not be an option in a Docker network (see e.g. here and here).

When I fire this script from a Ubuntu host, I can access the DB service at port 5433, and the web API at localhost:5154/swagger/index.html. Yet, when I run the action which should connect to the database, I get a connection refused error, even though I can clearly see the DB service IP and port:

"Exception":"Npgsql.NpgsqlException (0x80004005): Failed to connect to 172.27.0.2:5433  
---\u003E System.Net.Sockets.SocketException (111): Connection refused    
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.\u003COpen\u003Eg__OpenCore|191_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.\u003CGet\u003Eg__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.\u003COpen\u003Eg__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.Open()  
...

CodePudding user response:

When a container connects to another container on the bridge network, you use the container port. Not the mapped port on the host. So your connection string should be

CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5432;Database=postgres
  • Related