Search code examples
c#.net-coredocker-composeeventstoredb

Event Store connection was closed


With the following docker-compose file I start my .Net Core 3.1 Console application and an Event Store container.

version: "3.4"

services:
  eventstore:
    image: eventstore/eventstore
    networks:
      - eventnet
    ports:
      - "2113:2113"
      - "1113:1113"
  consoleapp4:
    image: ${DOCKER_REGISTRY-}consoleapp4
    build:
      context: .
      dockerfile: ConsoleApp4/Dockerfile
    depends_on:
      - eventstore

networks:
  eventnet:
    driver: bridge

After building/running the docker-compose file the EventStore UI is accessible on http://localhost:2113; so that one works.

My console is very simple, looking like this, but has troubles connecting. I get an unhandled exception of type

'EventStore.ClientAPI.Exceptions.ConnectionClosedException' occurred in System.Private.CoreLib.dll: 'Connection 'MyConName' was closed.':

using System;
using EventStore.ClientAPI;
using Newtonsoft.Json;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            var connectionSettings = ConnectionSettings.Create();
            connectionSettings.UseConsoleLogger().UseDebugLogger().EnableVerboseLogging().Build();

            var connection = EventStoreConnection.Create("ConnectTo=tcp://admin:changeit@localhost:1113", connectionSettings, "MyConName");
            connection.Connected += (a, b) =>
            {
                var x = 3; // Never comes here
            };

            connection.ErrorOccurred += (a, b) =>
            {
                var x = 5; // Never comes here
            };

            connection.ConnectAsync().Wait();
            var model = new MyModel();
            var item = new EventData(model.Id, model.GetTypeString(), true, model.GetByteArray(), new byte[] { });

            // Throws exception 'EventStore.ClientAPI.Exceptions.ConnectionClosedException'
            var result = connection.AppendToStreamAsync("mystream", 0, item).GetAwaiter().GetResult();
        }
    }

    class MyModel
    {
        public Guid Id { get; } = Guid.NewGuid();

        public string GetTypeString() => this.GetType().FullName.ToLower();

        public byte[] GetByteArray() => System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
    }
}

I have absolutely NO clue what to do anymore, so any pointer would be highly appreciated, it must be something simple right..?

I've tried another machine, started completely fresh, tried on IP address, another way of setting up the connection string, Powershell tells:

C:\WINDOWS\system32> Test-NetConnection -ComputerName localhost -Port 1113


ComputerName     : localhost
RemoteAddress    : ::1
RemotePort       : 1113
InterfaceAlias   : Loopback Pseudo-Interface 1
SourceAddress    : ::1
TcpTestSucceeded : True

Edit

After changing my docker-compose file to:

version: '3.4'

services:
  myeventstore:
    image: eventstore/eventstore
    ports:
      - "2113:2113"
      - "1113:1113"
  console:
    image: ${DOCKER_REGISTRY-}console
    build:
      context: .
      dockerfile: Console/Dockerfile
    depends_on:
      - myeventstore

or

version: '3.4'

services:
  myeventstore:
    image: eventstore/eventstore
    ports:
      - "2113:2113"
      - "1113:1113"
    networks:
      - eventsnet
  console:
    image: ${DOCKER_REGISTRY-}console
    build:
      context: .
      dockerfile: Console/Dockerfile
    depends_on:
      - myeventstore
    networks:
      - eventsnet

networks:
  eventsnet:
    driver: bridge

and the connection string to: myeventstore still no success...


Solution

  • Despite the fact I couldn't get this thing working like primarily asked I did manage to get things working, via SSL; with a self signed certificate.

    Dockerfile that creates the self-signed certificate, for development environment:

    FROM eventstore/eventstore
    RUN apt-get update -y \
      && apt-get install -y openssl \
      && openssl req -x509 -sha256 -nodes -days 3650 -subj "/CN=eventstore.org" -newkey rsa:2048 -keyout eventstore.pem -out eventstore.csr \
      && openssl pkcs12 -export -inkey eventstore.pem -in eventstore.csr -out eventstore.p12 -passout pass: \
      && openssl pkcs12 -export -inkey eventstore.pem -in eventstore.csr -out eventstore.pfx -passout pass: \
      && mkdir -p /usr/local/share/ca-certificates \
      && cp eventstore.csr /usr/local/share/ca-certificates/eventstore.crt \
      && update-ca-certificates \
      && apt-get autoremove \
      && apt-get clean \
      && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
    

    My docker-compose file looks like this:

    version: '3.4'
    
    services:
      myeventstore:
        image: eventstore/eventstore:with-cert-local
        build:
          context: .
          dockerfile: .docker/EventStore/Dockerfile
        ports:
          - "2113:2113"
          - "1113:1113"
          - "1115:1115"
        environment:
          - EVENTSTORE_CERTIFICATE_FILE=eventstore.p12 
          - EVENTSTORE_EXT_SECURE_TCP_PORT=1115 
    
      console:
        image: ${DOCKER_REGISTRY-}console
        build:
          context: .
          dockerfile: Console/Dockerfile
        depends_on:
          - myeventstore
    
    using System;
    using System.Text;
    using System.Threading.Tasks;
    using EventStore.ClientAPI;
    using Newtonsoft.Json;
    
    namespace Console
    {
        internal static class Program
        {
            private static async Task Main()
            {
                var connectionSettings = ConnectionSettings.Create();
                connectionSettings.EnableVerboseLogging()
                    .UseDebugLogger()
                    .UseConsoleLogger()
                    .SetHeartbeatTimeout(TimeSpan.FromSeconds(60))
                    .SetHeartbeatInterval(TimeSpan.FromSeconds(30));
    
                var connection = EventStoreConnection.Create(
                    "ConnectTo=tcp://myeventstore:1115;DefaultUserCredentials=admin:changeit;UseSslConnection=true;TargetHost=eventstore.org;ValidateServer=false",
                    connectionSettings, "MyConName");
    
                await connection.ConnectAsync();
    
                var model = new MyModel();
                var item = new EventData(model.Id, model.GetTypeString(), true, model.GetByteArray(), new byte[] { });
    
                var result = await connection.AppendToStreamAsync("mystream", ExpectedVersion.Any, item);
            }
        }
    
        public class MyModel : MyBaseEvent, IEventId
        {
            /// <inheritdoc />
            public Guid Id { get; } = Guid.NewGuid();
        }
    
        public abstract class MyBaseEvent
        {
            public string GetTypeString() => GetType().ToString().ToLower();
    
            public byte[] GetByteArray() => Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
        }
    
        public interface IEventId
        {
            Guid Id { get; }
        }
    }