diff --git a/.github/workflows/base.yml b/.github/workflows/base.yml
index b9b042301..c0c57f739 100644
--- a/.github/workflows/base.yml
+++ b/.github/workflows/base.yml
@@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- framework: [ net5.0, net6.0, net7.0 ]
+ framework: [ net6.0, net7.0, net8.0 ]
os: [ ubuntu-latest ]
test: [ Streams, PersistentSubscriptions, Operations, UserManagement, ProjectionManagement ]
configuration: [ release ]
@@ -33,9 +33,9 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
- 5.0.x
6.0.x
7.0.x
+ 8.0.x
- name: Compile
shell: bash
run: |
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 16e37e13d..31add45a8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,9 +4,9 @@ on:
pull_request:
push:
branches:
- - master
+ - master
tags:
- - v*
+ - v*
jobs:
test:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index f3d7df4f9..239ea739a 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- framework: [ net5.0, net6.0, net7.0 ]
+ framework: [ net6.0, net7.0, net8.0 ]
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
name: scan-vulnerabilities/${{ matrix.os }}/${{ matrix.framework }}
@@ -25,9 +25,9 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
- 5.0.x
6.0.x
7.0.x
+ 8.0.x
- name: Scan for Vulnerabilities
shell: bash
run: |
@@ -43,13 +43,13 @@ jobs:
strategy:
fail-fast: false
matrix:
- framework: [ net5.0, net6.0, net7.0 ]
+ framework: [ net8.0 ]
services:
esdb:
image: ghcr.io/eventstore/eventstore:lts
env:
EVENTSTORE_INSECURE: true
- EVENTSTORE_MEMDB: true
+ EVENTSTORE_MEM_DB: false
EVENTSTORE_RUN_PROJECTIONS: all
EVENTSTORE_START_STANDARD_PROJECTIONS: true
ports:
@@ -62,9 +62,7 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
- 5.0.x
- 6.0.x
- 7.0.x
+ 8.0.x
- name: Compile
shell: bash
run: |
@@ -79,7 +77,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- framework: [ net5.0, net6.0, net7.0 ]
+ framework: [ net6.0, net7.0, net8.0 ]
os: [ ubuntu-latest, windows-latest ]
configuration: [ release ]
runs-on: ${{ matrix.os }}
@@ -94,9 +92,9 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
- 5.0.x
6.0.x
7.0.x
+ 8.0.x
- name: Compile
shell: bash
run: |
@@ -132,9 +130,9 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
- 5.0.x
6.0.x
7.0.x
+ 8.0.x
- name: Dotnet Pack
shell: bash
run: |
diff --git a/Directory.Build.props b/Directory.Build.props
index 3ed57a184..eecbb8220 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,6 @@
- net5.0;net6.0;net7.0;
- x64
+ net6.0;net7.0;net8.0
true
enable
enable
@@ -14,7 +13,7 @@
pdbonly
true
- 2.49.0
- 2.50.0
+ 2.59.0
+ 2.59.0
diff --git a/EventStore.Client.sln.DotSettings b/EventStore.Client.sln.DotSettings
index 16d970453..f97c72463 100644
--- a/EventStore.Client.sln.DotSettings
+++ b/EventStore.Client.sln.DotSettings
@@ -26,16 +26,16 @@
<inspection_tool class="UnnecessaryReturnJS" enabled="false" level="WARNING" enabled_by_default="false" />
</profile></IDEA_SETTINGS><RIDER_SETTINGS><profile>
<Language id="CSS">
- <Rearrange>true</Rearrange>
<Reformat>true</Reformat>
+ <Rearrange>true</Rearrange>
</Language>
<Language id="EditorConfig">
<Reformat>true</Reformat>
</Language>
<Language id="HTML">
+ <Reformat>true</Reformat>
<OptimizeImports>false</OptimizeImports>
<Rearrange>true</Rearrange>
- <Reformat>true</Reformat>
</Language>
<Language id="HTTP Request">
<Reformat>true</Reformat>
@@ -53,9 +53,9 @@
<Reformat>true</Reformat>
</Language>
<Language id="JavaScript">
+ <Reformat>true</Reformat>
<OptimizeImports>false</OptimizeImports>
<Rearrange>true</Rearrange>
- <Reformat>true</Reformat>
</Language>
<Language id="Markdown">
<Reformat>true</Reformat>
@@ -73,9 +73,9 @@
<Reformat>true</Reformat>
</Language>
<Language id="XML">
+ <Reformat>true</Reformat>
<OptimizeImports>false</OptimizeImports>
<Rearrange>true</Rearrange>
- <Reformat>true</Reformat>
</Language>
<Language id="yaml">
<Reformat>true</Reformat>
@@ -402,4 +402,5 @@
True
True
True
+ True
True
\ No newline at end of file
diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props
index a3644b0a7..54497a508 100644
--- a/samples/Directory.Build.props
+++ b/samples/Directory.Build.props
@@ -1,10 +1,15 @@
- net5.0;net6.0;net7.0
+ net8.0
enable
enable
true
Exe
preview
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/Samples.sln.DotSettings b/samples/Samples.sln.DotSettings
index 16d970453..c341e4095 100644
--- a/samples/Samples.sln.DotSettings
+++ b/samples/Samples.sln.DotSettings
@@ -399,6 +399,7 @@
True
True
True
+ True
True
True
True
diff --git a/samples/appending-events/Program.cs b/samples/appending-events/Program.cs
index 4a908a3d1..2e1bb758f 100644
--- a/samples/appending-events/Program.cs
+++ b/samples/appending-events/Program.cs
@@ -1,161 +1,169 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using EventStore.Client;
-
-namespace appending_events {
- class Program {
- static async Task Main(string[] args) {
- var settings = EventStoreClientSettings.Create("esdb://localhost:2113?tls=false");
- settings.OperationOptions.ThrowOnAppendFailure = false;
- await using var client = new EventStoreClient(
- settings
- );
- await AppendToStream(client);
- await AppendWithConcurrencyCheck(client);
- await AppendWithNoStream(client);
- await AppendWithSameId(client);
-
- return 0;
- }
+#pragma warning disable CS8321 // Local function is declared but never used
+
+var settings = EventStoreClientSettings.Create("esdb://localhost:2113?tls=false");
+
+settings.OperationOptions.ThrowOnAppendFailure = false;
+
+await using var client = new EventStoreClient(settings);
+
+await AppendToStream(client);
+await AppendWithConcurrencyCheck(client);
+await AppendWithNoStream(client);
+await AppendWithSameId(client);
+
+return;
- private static async Task AppendToStream(EventStoreClient client) {
- #region append-to-stream
- var eventData = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"some value\"}")
- );
-
- await client.AppendToStreamAsync(
- "some-stream",
- StreamState.NoStream,
- new List {
- eventData
- });
- #endregion append-to-stream
+static async Task AppendToStream(EventStoreClient client) {
+ #region append-to-stream
+
+ var eventData = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"1\" \"value\": \"some value\"}"u8.ToArray()
+ );
+
+ await client.AppendToStreamAsync(
+ "some-stream",
+ StreamState.NoStream,
+ new List {
+ eventData
}
+ );
+
+ #endregion append-to-stream
+}
+
+static async Task AppendWithSameId(EventStoreClient client) {
+ #region append-duplicate-event
+
+ var eventData = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"1\" \"value\": \"some value\"}"u8.ToArray()
+ );
- private static async Task AppendWithSameId(EventStoreClient client) {
- #region append-duplicate-event
- var eventData = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"some value\"}")
- );
-
- await client.AppendToStreamAsync(
- "same-event-stream",
- StreamState.Any,
- new List {
- eventData
- });
-
- // attempt to append the same event again
- await client.AppendToStreamAsync(
- "same-event-stream",
- StreamState.Any,
- new List {
- eventData
- });
- #endregion append-duplicate-event
+ await client.AppendToStreamAsync(
+ "same-event-stream",
+ StreamState.Any,
+ new List {
+ eventData
}
+ );
+
+ // attempt to append the same event again
+ await client.AppendToStreamAsync(
+ "same-event-stream",
+ StreamState.Any,
+ new List {
+ eventData
+ }
+ );
+
+ #endregion append-duplicate-event
+}
- private static async Task AppendWithNoStream(EventStoreClient client) {
- #region append-with-no-stream
- var eventDataOne = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"some value\"}")
- );
-
- var eventDataTwo = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"2\" \"value\": \"some other value\"}")
- );
-
- await client.AppendToStreamAsync(
- "no-stream-stream",
- StreamState.NoStream,
- new List {
- eventDataOne
- });
-
- // attempt to append the same event again
- await client.AppendToStreamAsync(
- "no-stream-stream",
- StreamState.NoStream,
- new List {
- eventDataTwo
- });
- #endregion append-with-no-stream
+static async Task AppendWithNoStream(EventStoreClient client) {
+ #region append-with-no-stream
+
+ var eventDataOne = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"1\" \"value\": \"some value\"}"u8.ToArray()
+ );
+
+ var eventDataTwo = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"2\" \"value\": \"some other value\"}"u8.ToArray()
+ );
+
+ await client.AppendToStreamAsync(
+ "no-stream-stream",
+ StreamState.NoStream,
+ new List {
+ eventDataOne
}
+ );
+
+ // attempt to append the same event again
+ await client.AppendToStreamAsync(
+ "no-stream-stream",
+ StreamState.NoStream,
+ new List {
+ eventDataTwo
+ }
+ );
+
+ #endregion append-with-no-stream
+}
- private static async Task AppendWithConcurrencyCheck(EventStoreClient client) {
- await client.AppendToStreamAsync("concurrency-stream", StreamRevision.None,
- new[] {new EventData(Uuid.NewUuid(), "-", ReadOnlyMemory.Empty)});
- #region append-with-concurrency-check
-
- var clientOneRead = client.ReadStreamAsync(
- Direction.Forwards,
- "concurrency-stream",
- StreamPosition.Start);
- var clientOneRevision = (await clientOneRead.LastAsync()).Event.EventNumber.ToUInt64();
-
- var clientTwoRead = client.ReadStreamAsync(Direction.Forwards, "concurrency-stream", StreamPosition.Start);
- var clientTwoRevision = (await clientTwoRead.LastAsync()).Event.EventNumber.ToUInt64();
-
- var clientOneData = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"clientOne\"}")
- );
-
- await client.AppendToStreamAsync(
- "no-stream-stream",
- clientOneRevision,
- new List {
- clientOneData
- });
-
- var clientTwoData = new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"2\" \"value\": \"clientTwo\"}")
- );
-
- await client.AppendToStreamAsync(
- "no-stream-stream",
- clientTwoRevision,
- new List {
- clientTwoData
- });
- #endregion append-with-concurrency-check
+static async Task AppendWithConcurrencyCheck(EventStoreClient client) {
+ await client.AppendToStreamAsync(
+ "concurrency-stream",
+ StreamRevision.None,
+ new[] { new EventData(Uuid.NewUuid(), "-", ReadOnlyMemory.Empty) }
+ );
+
+ #region append-with-concurrency-check
+
+ var clientOneRead = client.ReadStreamAsync(
+ Direction.Forwards,
+ "concurrency-stream",
+ StreamPosition.Start
+ );
+
+ var clientOneRevision = (await clientOneRead.LastAsync()).Event.EventNumber.ToUInt64();
+
+ var clientTwoRead = client.ReadStreamAsync(Direction.Forwards, "concurrency-stream", StreamPosition.Start);
+ var clientTwoRevision = (await clientTwoRead.LastAsync()).Event.EventNumber.ToUInt64();
+
+ var clientOneData = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"1\" \"value\": \"clientOne\"}"u8.ToArray()
+ );
+
+ await client.AppendToStreamAsync(
+ "no-stream-stream",
+ clientOneRevision,
+ new List {
+ clientOneData
}
-
- protected async Task AppendOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken)
- {
- var eventData = new EventData(
- Uuid.NewUuid(),
- "TestEvent",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"some value\"}")
- );
-
- #region overriding-user-credentials
- await client.AppendToStreamAsync(
- "some-stream",
- StreamState.Any,
- new[] { eventData },
- userCredentials: new UserCredentials("admin", "changeit"),
- cancellationToken: cancellationToken
- );
- #endregion overriding-user-credentials
+ );
+
+ var clientTwoData = new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ "{\"id\": \"2\" \"value\": \"clientTwo\"}"u8.ToArray()
+ );
+
+ await client.AppendToStreamAsync(
+ "no-stream-stream",
+ clientTwoRevision,
+ new List {
+ clientTwoData
}
- }
+ );
+
+ #endregion append-with-concurrency-check
+}
+
+static async Task AppendOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken) {
+ var eventData = new EventData(
+ Uuid.NewUuid(),
+ "TestEvent",
+ "{\"id\": \"1\" \"value\": \"some value\"}"u8.ToArray()
+ );
+
+ #region overriding-user-credentials
+
+ await client.AppendToStreamAsync(
+ "some-stream",
+ StreamState.Any,
+ new[] { eventData },
+ userCredentials: new UserCredentials("admin", "changeit"),
+ cancellationToken: cancellationToken
+ );
+
+ #endregion overriding-user-credentials
}
diff --git a/samples/appending-events/appending-events.csproj b/samples/appending-events/appending-events.csproj
index 34b8399e9..fb93d800e 100644
--- a/samples/appending-events/appending-events.csproj
+++ b/samples/appending-events/appending-events.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/samples/connecting-to-a-cluster/Program.cs b/samples/connecting-to-a-cluster/Program.cs
index 67e4fba6d..a31666fc6 100644
--- a/samples/connecting-to-a-cluster/Program.cs
+++ b/samples/connecting-to-a-cluster/Program.cs
@@ -1,34 +1,33 @@
-using System;
-using System.Net;
-using EventStore.Client;
-
-namespace connecting_to_a_cluster {
- class Program {
- static void Main(string[] args) {
- }
-
- private static void ConnectingToACluster() {
- #region connecting-to-a-cluster
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://localhost:1114,localhost:2114,localhost:3114")
- );
- #endregion connecting-to-a-cluster
- }
-
- private static void ProvidingDefaultCredentials() {
- #region providing-default-credentials
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://admin:changeit@localhost:1114,localhost:2114,localhost:3114")
- );
- #endregion providing-default-credentials
- }
-
- private static void ConnectingToAClusterComplex() {
- #region connecting-to-a-cluster-complex
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://admin:changeit@localhost:1114,localhost:2114,localhost:3114?DiscoveryInterval=30000;GossipTimeout=10000;NodePreference=leader;MaxDiscoverAttempts=5")
- );
- #endregion connecting-to-a-cluster-complex
- }
- }
+#pragma warning disable CS8321 // Local function is declared but never used
+
+static void ConnectingToACluster() {
+ #region connecting-to-a-cluster
+
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create("esdb://localhost:1114,localhost:2114,localhost:3114")
+ );
+
+ #endregion connecting-to-a-cluster
+}
+
+static void ProvidingDefaultCredentials() {
+ #region providing-default-credentials
+
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create("esdb://admin:changeit@localhost:1114,localhost:2114,localhost:3114")
+ );
+
+ #endregion providing-default-credentials
}
+
+static void ConnectingToAClusterComplex() {
+ #region connecting-to-a-cluster-complex
+
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create(
+ "esdb://admin:changeit@localhost:1114,localhost:2114,localhost:3114?DiscoveryInterval=30000;GossipTimeout=10000;NodePreference=leader;MaxDiscoverAttempts=5"
+ )
+ );
+
+ #endregion connecting-to-a-cluster-complex
+}
\ No newline at end of file
diff --git a/samples/connecting-to-a-cluster/connecting-to-a-cluster.csproj b/samples/connecting-to-a-cluster/connecting-to-a-cluster.csproj
index 1d8ff5b7d..4754bd0e2 100644
--- a/samples/connecting-to-a-cluster/connecting-to-a-cluster.csproj
+++ b/samples/connecting-to-a-cluster/connecting-to-a-cluster.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/samples/connecting-to-a-single-node/DemoInterceptor.cs b/samples/connecting-to-a-single-node/DemoInterceptor.cs
index 6f01bf72a..fc68b70a2 100644
--- a/samples/connecting-to-a-single-node/DemoInterceptor.cs
+++ b/samples/connecting-to-a-single-node/DemoInterceptor.cs
@@ -1,28 +1,31 @@
-using System;
using Grpc.Core;
using Grpc.Core.Interceptors;
-namespace connecting_to_a_single_node {
- #region interceptor
- public class DemoInterceptor : Interceptor {
- public override AsyncServerStreamingCall
- AsyncServerStreamingCall(
- TRequest request,
- ClientInterceptorContext context,
- AsyncServerStreamingCallContinuation continuation) {
- Console.WriteLine($"AsyncServerStreamingCall: {context.Method.FullName}");
+namespace connecting_to_a_single_node;
- return base.AsyncServerStreamingCall(request, context, continuation);
- }
+#region interceptor
- public override AsyncClientStreamingCall
- AsyncClientStreamingCall(
- ClientInterceptorContext context,
- AsyncClientStreamingCallContinuation continuation) {
- Console.WriteLine($"AsyncClientStreamingCall: {context.Method.FullName}");
+public class DemoInterceptor : Interceptor {
+ public override AsyncServerStreamingCall
+ AsyncServerStreamingCall(
+ TRequest request,
+ ClientInterceptorContext context,
+ AsyncServerStreamingCallContinuation continuation
+ ) {
+ Console.WriteLine($"AsyncServerStreamingCall: {context.Method.FullName}");
- return base.AsyncClientStreamingCall(context, continuation);
- }
+ return base.AsyncServerStreamingCall(request, context, continuation);
+ }
+
+ public override AsyncClientStreamingCall
+ AsyncClientStreamingCall(
+ ClientInterceptorContext context,
+ AsyncClientStreamingCallContinuation continuation
+ ) {
+ Console.WriteLine($"AsyncClientStreamingCall: {context.Method.FullName}");
+
+ return base.AsyncClientStreamingCall(context, continuation);
}
- #endregion interceptor
}
+
+#endregion interceptor
\ No newline at end of file
diff --git a/samples/connecting-to-a-single-node/Program.cs b/samples/connecting-to-a-single-node/Program.cs
index 192327ba5..f50e1689f 100644
--- a/samples/connecting-to-a-single-node/Program.cs
+++ b/samples/connecting-to-a-single-node/Program.cs
@@ -1,80 +1,85 @@
-using System;
-using System.Net.Http;
-using EventStore.Client;
+using connecting_to_a_single_node;
-namespace connecting_to_a_single_node {
- class Program {
- static void Main(string[] args) {
- }
+#pragma warning disable CS8321 // Local function is declared but never used
- private static void SimpleConnection() {
- #region creating-simple-connection
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://localhost:2113")
- );
- #endregion creating-simple-connection
- }
+static void SimpleConnection() {
+ #region creating-simple-connection
- private static void ProvidingDefaultCredentials() {
- #region providing-default-credentials
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://admin:changeit@localhost:2113")
- );
- #endregion providing-default-credentials
- }
+ using var client = new EventStoreClient(EventStoreClientSettings.Create("esdb://localhost:2113"));
- private static void SpecifyingAConnectionName() {
- #region setting-the-connection-name
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://admin:changeit@localhost:2113?ConnectionName=SomeConnection")
- );
- #endregion setting-the-connection-name
- }
+ #endregion creating-simple-connection
+}
- private static void OverridingTheTimeout() {
- #region overriding-timeout
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create($"esdb://admin:changeit@localhost:2113?OperationTimeout=30000")
- );
- #endregion overriding-timeout
- }
-
- private static void CombiningSettings() {
- #region overriding-timeout
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create($"esdb://admin:changeit@localhost:2113?ConnectionName=SomeConnection&OperationTimeout=30000")
- );
- #endregion overriding-timeout
- }
+static void ProvidingDefaultCredentials() {
+ #region providing-default-credentials
- private static void CreatingAnInterceptor() {
- #region adding-an-interceptor
- var settings = new EventStoreClientSettings {
- Interceptors = new[] {new DemoInterceptor()},
- ConnectivitySettings = {
- Address = new Uri("https://localhost:2113")
- }
- };
- #endregion adding-an-interceptor
-
- var client = new EventStoreClient(settings);
- }
+ using var client = new EventStoreClient(EventStoreClientSettings.Create("esdb://admin:changeit@localhost:2113"));
+
+ #endregion providing-default-credentials
+}
+
+static void SpecifyingAConnectionName() {
+ #region setting-the-connection-name
+
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create("esdb://admin:changeit@localhost:2113?ConnectionName=SomeConnection")
+ );
+
+ #endregion setting-the-connection-name
+}
+
+static void OverridingTheTimeout() {
+ #region overriding-timeout
- private static void CustomHttpMessageHandler() {
- #region adding-an-custom-http-message-handler
- var settings = new EventStoreClientSettings {
- CreateHttpMessageHandler = () =>
- new HttpClientHandler {
- ServerCertificateCustomValidationCallback =
- (sender, cert, chain, sslPolicyErrors) => true
- },
- ConnectivitySettings = {
- Address = new Uri("https://localhost:2113")
- }
- };
- #endregion adding-an-custom-http-message-handler
-
- var client = new EventStoreClient(settings);
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create($"esdb://admin:changeit@localhost:2113?OperationTimeout=30000")
+ );
+
+ #endregion overriding-timeout
+}
+
+static void CombiningSettings() {
+ #region overriding-timeout
+
+ using var client = new EventStoreClient(
+ EventStoreClientSettings.Create(
+ $"esdb://admin:changeit@localhost:2113?ConnectionName=SomeConnection&OperationTimeout=30000"
+ )
+ );
+
+ #endregion overriding-timeout
+}
+
+static void CreatingAnInterceptor() {
+ #region adding-an-interceptor
+
+ var settings = new EventStoreClientSettings {
+ Interceptors = new[] { new DemoInterceptor() },
+ ConnectivitySettings = {
+ Address = new Uri("https://localhost:2113")
}
- }
+ };
+
+ #endregion adding-an-interceptor
+
+ var client = new EventStoreClient(settings);
}
+
+static void CustomHttpMessageHandler() {
+ #region adding-an-custom-http-message-handler
+
+ var settings = new EventStoreClientSettings {
+ CreateHttpMessageHandler = () =>
+ new HttpClientHandler {
+ ServerCertificateCustomValidationCallback =
+ (sender, cert, chain, sslPolicyErrors) => true
+ },
+ ConnectivitySettings = {
+ Address = new Uri("https://localhost:2113")
+ }
+ };
+
+ #endregion adding-an-custom-http-message-handler
+
+ var client = new EventStoreClient(settings);
+}
\ No newline at end of file
diff --git a/samples/connecting-to-a-single-node/connecting-to-a-single-node.csproj b/samples/connecting-to-a-single-node/connecting-to-a-single-node.csproj
index 337b66b85..4ef794ee4 100644
--- a/samples/connecting-to-a-single-node/connecting-to-a-single-node.csproj
+++ b/samples/connecting-to-a-single-node/connecting-to-a-single-node.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/samples/persistent-subscriptions/Program.cs b/samples/persistent-subscriptions/Program.cs
index f26348917..6ea61fa67 100644
--- a/samples/persistent-subscriptions/Program.cs
+++ b/samples/persistent-subscriptions/Program.cs
@@ -1,235 +1,298 @@
-using System;
-using System.Threading.Tasks;
-using EventStore.Client;
-
-namespace persistent_subscriptions
-{
- class Program
- {
- static async Task Main(string[] args) {
- await using var client = new EventStorePersistentSubscriptionsClient(
- EventStoreClientSettings.Create("esdb://localhost:2113?tls=false")
- );
- await CreatePersistentSubscription(client);
- await UpdatePersistentSubscription(client);
- await ConnectToPersistentSubscriptionToStream(client);
- await CreatePersistentSubscriptionToAll(client);
- await ConnectToPersistentSubscriptionToAll(client);
- await ConnectToPersistentSubscriptionWithManualAcks(client);
- await GetPersistentSubscriptionToStreamInfo(client);
- await GetPersistentSubscriptionToAllInfo(client);
- await ReplayParkedToStream(client);
- await ReplayParkedToAll(client);
- await ListPersistentSubscriptionsToStream(client);
- await ListPersistentSubscriptionsToAll(client);
- await ListAllPersistentSubscriptions(client);
- await RestartPersistentSubscriptionSubsystem(client);
- await DeletePersistentSubscription(client);
- }
-
- static async Task CreatePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
- #region create-persistent-subscription-to-stream
- var userCredentials = new UserCredentials("admin", "changeit");
-
- var settings = new PersistentSubscriptionSettings();
- await client.CreateToStreamAsync(
- "test-stream",
- "subscription-group",
- settings,
- userCredentials: userCredentials);
- #endregion create-persistent-subscription-to-stream
- }
-
- static async Task ConnectToPersistentSubscriptionToStream(EventStorePersistentSubscriptionsClient client) {
- #region subscribe-to-persistent-subscription-to-stream
- var subscription = await client.SubscribeToStreamAsync(
- "test-stream",
- "subscription-group",
- async (subscription, evnt, retryCount, cancellationToken) => {
- await HandleEvent(evnt);
- await subscription.Ack(evnt);
- }, (subscription, dropReason, exception) => {
- Console.WriteLine($"Subscription was dropped due to {dropReason}. {exception}");
- });
- #endregion subscribe-to-persistent-subscription-to-stream
- }
-
- static async Task CreatePersistentSubscriptionToAll(EventStorePersistentSubscriptionsClient client) {
- #region create-persistent-subscription-to-all
- var userCredentials = new UserCredentials("admin", "changeit");
- var filter = StreamFilter.Prefix("test");
-
- var settings = new PersistentSubscriptionSettings();
- await client.CreateToAllAsync(
- "subscription-group",
- filter,
- settings,
- userCredentials: userCredentials);
- #endregion create-persistent-subscription-to-all
- }
-
- static async Task ConnectToPersistentSubscriptionToAll(EventStorePersistentSubscriptionsClient client) {
- #region subscribe-to-persistent-subscription-to-all
- await client.SubscribeToAllAsync(
- "subscription-group",
- async (subscription, evnt, retryCount, cancellationToken) => {
- await HandleEvent(evnt);
- }, (subscription, dropReason, exception) => {
- Console.WriteLine($"Subscription was dropped due to {dropReason}. {exception}");
- });
- #endregion subscribe-to-persistent-subscription-to-all
- }
-
- static async Task ConnectToPersistentSubscriptionWithManualAcks(EventStorePersistentSubscriptionsClient client) {
- #region subscribe-to-persistent-subscription-with-manual-acks
- var subscription = await client.SubscribeToStreamAsync(
- "test-stream",
- "subscription-group",
- async (subscription, evnt, retryCount, cancellationToken) => {
- try {
- await HandleEvent(evnt);
- await subscription.Ack(evnt);
- } catch (UnrecoverableException ex) {
- await subscription.Nack(PersistentSubscriptionNakEventAction.Park, ex.Message, evnt);
- }
- }, (subscription, dropReason, exception) => {
- Console.WriteLine($"Subscription was dropped due to {dropReason}. {exception}");
- });
- #endregion subscribe-to-persistent-subscription-with-manual-acks
- }
-
- static async Task UpdatePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
- #region update-persistent-subscription
- var userCredentials = new UserCredentials("admin", "changeit");
- var settings = new PersistentSubscriptionSettings(
- resolveLinkTos: true,
- checkPointLowerBound: 20);
-
- await client.UpdateToStreamAsync(
- "test-stream",
- "subscription-group",
- settings,
- userCredentials: userCredentials);
- #endregion update-persistent-subscription
- }
-
- static async Task DeletePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
- #region delete-persistent-subscription
- var userCredentials = new UserCredentials("admin", "changeit");
- await client.DeleteToStreamAsync(
- "test-stream",
- "subscription-group",
- userCredentials: userCredentials);
- #endregion delete-persistent-subscription
- }
-
- static async Task GetPersistentSubscriptionToStreamInfo(EventStorePersistentSubscriptionsClient client) {
- #region get-persistent-subscription-to-stream-info
-
- var userCredentials = new UserCredentials("admin", "changeit");
- var info = await client.GetInfoToStreamAsync(
- "test-stream",
- "subscription-group",
- userCredentials: userCredentials);
-
- Console.WriteLine($"GroupName: {info.GroupName}, EventSource: {info.EventSource}, Status: {info.Status}");
-
- #endregion get-persistent-subscription-to-stream-info
- }
-
- static async Task GetPersistentSubscriptionToAllInfo(EventStorePersistentSubscriptionsClient client) {
- #region get-persistent-subscription-to-all-info
-
- var userCredentials = new UserCredentials("admin", "changeit");
- var info = await client.GetInfoToAllAsync(
- "subscription-group",
- userCredentials: userCredentials);
-
- Console.WriteLine($"GroupName: {info.GroupName}, EventSource: {info.EventSource}, Status: {info.Status}");
-
- #endregion get-persistent-subscription-to-all-info
- }
-
- static async Task ReplayParkedToStream(EventStorePersistentSubscriptionsClient client) {
- #region replay-parked-of-persistent-subscription-to-stream
-
- var userCredentials = new UserCredentials("admin", "changeit");
- await client.ReplayParkedMessagesToStreamAsync(
- "test-stream",
- "subscription-group",
- stopAt: 10,
- userCredentials: userCredentials);
-
- #endregion persistent-subscription-replay-parked-to-stream
- }
-
- static async Task ReplayParkedToAll(EventStorePersistentSubscriptionsClient client) {
- #region replay-parked-of-persistent-subscription-to-all
-
- var userCredentials = new UserCredentials("admin", "changeit");
- await client.ReplayParkedMessagesToAllAsync(
- "subscription-group",
- stopAt: 10,
- userCredentials: userCredentials);
-
- #endregion replay-parked-of-persistent-subscription-to-all
- }
-
- static async Task ListPersistentSubscriptionsToStream(EventStorePersistentSubscriptionsClient client) {
- #region list-persistent-subscriptions-to-stream
-
- var userCredentials = new UserCredentials("admin", "changeit");
- var subscriptions = await client.ListToStreamAsync(
- "test-stream",
- userCredentials: userCredentials);
-
- foreach (var s in subscriptions) {
- Console.WriteLine($"GroupName: {s.GroupName}, EventSource: {s.EventSource}, Status: {s.Status}");
- }
-
- #endregion list-persistent-subscriptions-to-stream
- }
-
- static async Task ListPersistentSubscriptionsToAll(EventStorePersistentSubscriptionsClient client) {
- #region list-persistent-subscriptions-to-all
-
- var userCredentials = new UserCredentials("admin", "changeit");
- var subscriptions = await client.ListToAllAsync(userCredentials: userCredentials);
-
- foreach (var s in subscriptions) {
- Console.WriteLine($"GroupName: {s.GroupName}, EventSource: {s.EventSource}, Status: {s.Status}");
- }
-
- #endregion list-persistent-subscriptions-to-all
- }
-
- static async Task ListAllPersistentSubscriptions(EventStorePersistentSubscriptionsClient client) {
- #region list-persistent-subscriptions
-
- var userCredentials = new UserCredentials("admin", "changeit");
- var subscriptions = await client.ListAllAsync(userCredentials: userCredentials);
-
- foreach (var s in subscriptions) {
- Console.WriteLine($"GroupName: {s.GroupName}, EventSource: {s.EventSource}, Status: {s.Status}");
- }
-
- #endregion list-persistent-subscriptions
- }
-
- static async Task RestartPersistentSubscriptionSubsystem(EventStorePersistentSubscriptionsClient client) {
- #region restart-persistent-subscription-subsystem
-
- var userCredentials = new UserCredentials("admin", "changeit");
- await client.RestartSubsystemAsync(userCredentials: userCredentials);
-
- #endregion restart-persistent-subscription-subsystem
- }
-
- static Task HandleEvent(ResolvedEvent evnt) {
- return Task.CompletedTask;
- }
-
- class UnrecoverableException : Exception {
- }
- }
+await using var client = new EventStorePersistentSubscriptionsClient(
+ EventStoreClientSettings.Create("esdb://localhost:2113?tls=false&tlsVerifyCert=false")
+);
+
+await DeletePersistentSubscription(client);
+await DeletePersistentSubscriptionToAll(client);
+
+await CreatePersistentSubscription(client);
+await UpdatePersistentSubscription(client);
+await ConnectToPersistentSubscriptionToStream(client);
+await CreatePersistentSubscriptionToAll(client);
+await ConnectToPersistentSubscriptionToAll(client);
+await ConnectToPersistentSubscriptionWithManualAcks(client);
+await GetPersistentSubscriptionToStreamInfo(client);
+await GetPersistentSubscriptionToAllInfo(client);
+await ReplayParkedToStream(client);
+await ReplayParkedToAll(client);
+await ListPersistentSubscriptionsToStream(client);
+await ListPersistentSubscriptionsToAll(client);
+await ListAllPersistentSubscriptions(client);
+await RestartPersistentSubscriptionSubsystem(client);
+
+await DeletePersistentSubscription(client);
+await DeletePersistentSubscriptionToAll(client);
+
+return;
+
+static async Task CreatePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
+ #region create-persistent-subscription-to-stream
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+
+ var settings = new PersistentSubscriptionSettings();
+ await client.CreateToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ settings,
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Subscription to stream created");
+ #endregion create-persistent-subscription-to-stream
+}
+
+static async Task ConnectToPersistentSubscriptionToStream(EventStorePersistentSubscriptionsClient client) {
+ #region subscribe-to-persistent-subscription-to-stream
+
+ var subscription = await client.SubscribeToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ async (subscription, evnt, retryCount, cancellationToken) => {
+ await HandleEvent(evnt);
+ await subscription.Ack(evnt);
+ },
+ (subscription, dropReason, exception) => {
+ Console.WriteLine($"Subscription to stream was dropped due to {dropReason}. {exception?.Message}");
+ }
+ );
+
+ Console.WriteLine("Subscription to stream started");
+ #endregion subscribe-to-persistent-subscription-to-stream
+}
+
+static async Task CreatePersistentSubscriptionToAll(EventStorePersistentSubscriptionsClient client) {
+ #region create-persistent-subscription-to-all
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var filter = StreamFilter.Prefix("test");
+
+ var settings = new PersistentSubscriptionSettings();
+ await client.CreateToAllAsync(
+ "subscription-group",
+ filter,
+ settings,
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Subscription to all created");
+ #endregion create-persistent-subscription-to-all
+}
+
+static async Task ConnectToPersistentSubscriptionToAll(EventStorePersistentSubscriptionsClient client) {
+ #region subscribe-to-persistent-subscription-to-all
+
+ await client.SubscribeToAllAsync(
+ "subscription-group",
+ async (subscription, evnt, retryCount, cancellationToken) => { await HandleEvent(evnt); },
+ (subscription, dropReason, exception) => {
+ Console.WriteLine($"Subscription to all was dropped due to {dropReason}. {exception?.Message}");
+ }
+ );
+
+ Console.WriteLine("Subscription to all started");
+ #endregion subscribe-to-persistent-subscription-to-all
+}
+
+static async Task ConnectToPersistentSubscriptionWithManualAcks(EventStorePersistentSubscriptionsClient client) {
+ #region subscribe-to-persistent-subscription-with-manual-acks
+
+ var subscription = await client.SubscribeToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ async (subscription, evnt, retryCount, cancellationToken) => {
+ try {
+ await HandleEvent(evnt);
+ await subscription.Ack(evnt);
+ }
+ catch (UnrecoverableException ex) {
+ await subscription.Nack(PersistentSubscriptionNakEventAction.Park, ex.Message, evnt);
+ }
+ },
+ (subscription, dropReason, exception) => {
+ Console.WriteLine($"Subscription to stream with manual acks was dropped due to {dropReason}. {exception?.Message}");
+ }
+ );
+
+ Console.WriteLine("Subscription to stream with manual acks started");
+ #endregion subscribe-to-persistent-subscription-with-manual-acks
+}
+
+static async Task UpdatePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
+ #region update-persistent-subscription
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var settings = new PersistentSubscriptionSettings(true, checkPointLowerBound: 20);
+
+ await client.UpdateToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ settings,
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Subscription updated");
+ #endregion update-persistent-subscription
+}
+
+static async Task DeletePersistentSubscription(EventStorePersistentSubscriptionsClient client) {
+ #region delete-persistent-subscription
+
+ try {
+ var userCredentials = new UserCredentials("admin", "changeit");
+ await client.DeleteToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Subscription to stream deleted");
+ }
+ catch (PersistentSubscriptionNotFoundException) {
+ // ignore
+ }
+ catch (Exception ex) {
+ Console.WriteLine($"Subscription to stream delete error: {ex.GetType()} {ex.Message}");
+ }
+
+ #endregion delete-persistent-subscription
+}
+
+static async Task DeletePersistentSubscriptionToAll(EventStorePersistentSubscriptionsClient client) {
+ #region delete-persistent-subscription-to-all
+
+ try {
+ var userCredentials = new UserCredentials("admin", "changeit");
+ await client.DeleteToAllAsync(
+ "subscription-group",
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Subscription to all deleted");
+ }
+ catch (PersistentSubscriptionNotFoundException) {
+ // ignore
+ }
+ catch (Exception ex) {
+ Console.WriteLine($"Subscription to all delete error: {ex.GetType()} {ex.Message}");
+ }
+
+ #endregion delete-persistent-subscription-to-all
+}
+
+static async Task GetPersistentSubscriptionToStreamInfo(EventStorePersistentSubscriptionsClient client) {
+ #region get-persistent-subscription-to-stream-info
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var info = await client.GetInfoToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine($"GroupName: {info.GroupName} EventSource: {info.EventSource} Status: {info.Status}");
+
+ #endregion get-persistent-subscription-to-stream-info
+}
+
+static async Task GetPersistentSubscriptionToAllInfo(EventStorePersistentSubscriptionsClient client) {
+ #region get-persistent-subscription-to-all-info
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var info = await client.GetInfoToAllAsync(
+ "subscription-group",
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine($"GroupName: {info.GroupName} EventSource: {info.EventSource} Status: {info.Status}");
+
+ #endregion get-persistent-subscription-to-all-info
+}
+
+static async Task ReplayParkedToStream(EventStorePersistentSubscriptionsClient client) {
+ #region replay-parked-of-persistent-subscription-to-stream
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ await client.ReplayParkedMessagesToStreamAsync(
+ "test-stream",
+ "subscription-group",
+ 10,
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Replay of parked messages to stream requested");
+ #endregion persistent-subscription-replay-parked-to-stream
+}
+
+static async Task ReplayParkedToAll(EventStorePersistentSubscriptionsClient client) {
+ #region replay-parked-of-persistent-subscription-to-all
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ await client.ReplayParkedMessagesToAllAsync(
+ "subscription-group",
+ 10,
+ userCredentials: userCredentials
+ );
+
+ Console.WriteLine("Replay of parked messages to all requested");
+ #endregion replay-parked-of-persistent-subscription-to-all
}
+
+static async Task ListPersistentSubscriptionsToStream(EventStorePersistentSubscriptionsClient client) {
+ #region list-persistent-subscriptions-to-stream
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var subscriptions = await client.ListToStreamAsync(
+ "test-stream",
+ userCredentials: userCredentials
+ );
+
+ var entries = subscriptions
+ .Select(s => $"GroupName: {s.GroupName} EventSource: {s.EventSource} Status: {s.Status}");
+
+ Console.WriteLine($"Subscriptions to stream: [ {string.Join(", ", entries)} ]");
+
+ #endregion list-persistent-subscriptions-to-stream
+}
+
+static async Task ListPersistentSubscriptionsToAll(EventStorePersistentSubscriptionsClient client) {
+ #region list-persistent-subscriptions-to-all
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var subscriptions = await client.ListToAllAsync(userCredentials: userCredentials);
+
+ var entries = subscriptions
+ .Select(s => $"GroupName: {s.GroupName} EventSource: {s.EventSource} Status: {s.Status}");
+
+ Console.WriteLine($"Subscriptions to all: [ {string.Join(", ", entries)} ]");
+
+ #endregion list-persistent-subscriptions-to-all
+}
+
+static async Task ListAllPersistentSubscriptions(EventStorePersistentSubscriptionsClient client) {
+ #region list-persistent-subscriptions
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ var subscriptions = await client.ListAllAsync(userCredentials: userCredentials);
+
+ var entries = subscriptions
+ .Select(s => $"GroupName: {s.GroupName} EventSource: {s.EventSource} Status: {s.Status}");
+
+ Console.WriteLine($"Subscriptions: [{string.Join(", ", entries)} ]");
+
+ #endregion list-persistent-subscriptions
+}
+
+static async Task RestartPersistentSubscriptionSubsystem(EventStorePersistentSubscriptionsClient client) {
+ #region restart-persistent-subscription-subsystem
+
+ var userCredentials = new UserCredentials("admin", "changeit");
+ await client.RestartSubsystemAsync(userCredentials: userCredentials);
+
+ Console.WriteLine("Persistent subscription subsystem restarted");
+ #endregion restart-persistent-subscription-subsystem
+}
+
+static Task HandleEvent(ResolvedEvent evnt) => Task.CompletedTask;
+
+class UnrecoverableException : Exception { }
\ No newline at end of file
diff --git a/samples/projection-management/Program.cs b/samples/projection-management/Program.cs
index e864551dc..0f3d66b70 100644
--- a/samples/projection-management/Program.cs
+++ b/samples/projection-management/Program.cs
@@ -1,208 +1,235 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Text;
+#pragma warning disable CS8321 // Local function is declared but never used
+
using System.Text.Json;
-using System.Threading.Tasks;
-using EventStore.Client;
using Grpc.Core;
-namespace projection_management {
- public static class Program {
-
- ///
- /// This sample demonstrate the projection management features.
- /// It will create data in the target database.
- /// It will create a series of projections with the following content
- /// fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();
- ///
- private static async Task Main() {
-
- const string connection = "esdb://localhost:2113?tls=false";
- var managementClient = ManagementClient(connection);
-
- Console.WriteLine("Populate data");
- await Populate(connection, 100);
- Console.WriteLine("RestartSubSystem");
- await RestartSubSystem(managementClient);
- await Task.Delay(500); // give time to the subsystem to restart
-
- Console.WriteLine("Disable");
- await Disable(managementClient);
- Console.WriteLine("Disable Not Found");
- await DisableNotFound(managementClient);
-
- Console.WriteLine("Enable");
- await Enable(managementClient);
- Console.WriteLine("Enable Not Found");
- await EnableNotFound(managementClient);
-
- Console.WriteLine("Delete");
- await Delete(managementClient);
-
- Console.WriteLine("Abort");
- await Abort(managementClient);
- Console.WriteLine("Abort Not Found");
- await Abort_NotFound(managementClient);
-
- Console.WriteLine("Reset");
- await Reset(managementClient);
- Console.WriteLine("Reset Not Found");
- await Reset_NotFound(managementClient);
-
- Console.WriteLine("CreateContinuous");
- await CreateContinuous(managementClient);
- Console.WriteLine("CreateContinuous conflict");
- await CreateContinuous_Conflict(managementClient);
- //Console.WriteLine("CreateOneTime");
- //await CreateOneTime(managementClient);
- Console.WriteLine("Update");
- await Update(managementClient);
- Console.WriteLine("Update_NotFound");
- await Update_NotFound(managementClient);
- Console.WriteLine("ListAll");
- await ListAll(managementClient);
- Console.WriteLine("ListContinuous");
- await ListContinuous(managementClient);
- Console.WriteLine("GetStatus");
- await GetStatus(managementClient);
- // Console.WriteLine("GetState");
- // await GetState(managementClient);
- Console.WriteLine("GetResult");
- await GetResult(managementClient);
- }
-
-
-
- private static EventStoreProjectionManagementClient ManagementClient(string connection) {
-
- #region createClient
- var settings = EventStoreClientSettings.Create(connection);
- settings.ConnectionName = "Projection management client";
- settings.DefaultCredentials = new UserCredentials("admin", "changeit");
- var managementClient = new EventStoreProjectionManagementClient(settings);
- #endregion createClient
-
- return managementClient;
- }
- private static async Task RestartSubSystem(EventStoreProjectionManagementClient managementClient) {
- #region RestartSubSystem
- await managementClient.RestartSubsystemAsync();
- #endregion RestartSubSystem
- }
-
- private static async Task Disable(EventStoreProjectionManagementClient managementClient) {
- #region Disable
- await managementClient.DisableAsync("$by_category");
- #endregion Disable
- }
-
- private static async Task DisableNotFound(EventStoreProjectionManagementClient managementClient) {
- #region DisableNotFound
- try {
- await managementClient.DisableAsync("projection that does not exists");
- } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
- Console.WriteLine(e.Message);
- }
- #endregion DisableNotFound
- }
-
- private static async Task Enable(EventStoreProjectionManagementClient managementClient) {
- #region Enable
- await managementClient.EnableAsync("$by_category");
- #endregion Enable
- }
-
- private static async Task EnableNotFound(EventStoreProjectionManagementClient managementClient) {
- #region EnableNotFound
- try {
- await managementClient.EnableAsync("projection that does not exists");
- } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
- Console.WriteLine(e.Message);
- }
- #endregion EnableNotFound
- }
-
- private static Task Delete(EventStoreProjectionManagementClient managementClient) {
- #region Delete
- // this is not yet available in the .net grpc client
- #endregion Delete
-
- return Task.CompletedTask;
- }
-
- private static async Task Abort(EventStoreProjectionManagementClient managementClient) {
- try {
- var js =
- "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
- await managementClient.CreateContinuousAsync("countEvents_Abort", js);
- } catch (RpcException e) when (e.StatusCode is StatusCode.Aborted) {
- // ignore was already created in a previous run
- } catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
- // ignore was already created in a previous run
- }
-
- #region Abort
- // The .net clients prior to version 21.6 had an incorrect behavior: they will save the checkpoint.
- await managementClient.AbortAsync("countEvents_Abort");
- #endregion Abort
- }
-
- private static async Task Abort_NotFound(EventStoreProjectionManagementClient managementClient) {
- #region Abort_NotFound
- try {
- await managementClient.AbortAsync("projection that does not exists");
- } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
- Console.WriteLine(e.Message);
- }
- #endregion Abort_NotFound
- }
-
- private static async Task Reset(EventStoreProjectionManagementClient managementClient) {
- try {
- var js =
- "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
- await managementClient.CreateContinuousAsync("countEvents_Reset", js);
- } catch (RpcException e) when (e.StatusCode is StatusCode.Internal) {
- // ignore was already created in a previous run
- } catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
- // ignore was already created in a previous run
- }
-
- #region Reset
- // Checkpoint will be written prior to resetting the projection
- await managementClient.ResetAsync("countEvents_Reset");
- #endregion Reset
-
- }
-
- private static async Task Reset_NotFound(EventStoreProjectionManagementClient managementClient) {
- #region Reset_NotFound
- try {
- await managementClient.ResetAsync("projection that does not exists");
- } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
- Console.WriteLine(e.Message);
- }
- #endregion Reset_NotFound
- }
-
- private static async Task CreateOneTime(EventStoreProjectionManagementClient managementClient) {
- const string js =
- "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
- await managementClient.CreateOneTimeAsync(js);
- }
-
- private static async Task CreateContinuous(EventStoreProjectionManagementClient managementClient) {
- #region CreateContinuous
- const string js = @"fromAll()
+//// This sample demonstrate the projection management features.
+//// It will create data in the target database.
+//// It will create a series of projections with the following content
+//// fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();
+
+const string connection = "esdb://localhost:2113?tls=false";
+
+var managementClient = ManagementClient(connection);
+
+Console.WriteLine("Populate data");
+await Populate(connection, 100);
+Console.WriteLine("RestartSubSystem");
+await RestartSubSystem(managementClient);
+await Task.Delay(500); // give time to the subsystem to restart
+
+Console.WriteLine("Disable");
+await Disable(managementClient);
+Console.WriteLine("Disable Not Found");
+await DisableNotFound(managementClient);
+
+Console.WriteLine("Enable");
+await Enable(managementClient);
+Console.WriteLine("Enable Not Found");
+await EnableNotFound(managementClient);
+
+Console.WriteLine("Delete");
+await Delete(managementClient);
+
+Console.WriteLine("Abort");
+await Abort(managementClient);
+Console.WriteLine("Abort Not Found");
+await Abort_NotFound(managementClient);
+
+Console.WriteLine("Reset");
+await Reset(managementClient);
+Console.WriteLine("Reset Not Found");
+await Reset_NotFound(managementClient);
+
+Console.WriteLine("CreateContinuous");
+await CreateContinuous(managementClient);
+Console.WriteLine("CreateContinuous conflict");
+await CreateContinuous_Conflict(managementClient);
+//Console.WriteLine("CreateOneTime");
+//await CreateOneTime(managementClient);
+Console.WriteLine("Update");
+await Update(managementClient);
+Console.WriteLine("Update_NotFound");
+await Update_NotFound(managementClient);
+Console.WriteLine("ListAll");
+await ListAll(managementClient);
+Console.WriteLine("ListContinuous");
+await ListContinuous(managementClient);
+Console.WriteLine("GetStatus");
+await GetStatus(managementClient);
+// Console.WriteLine("GetState");
+// await GetState(managementClient);
+Console.WriteLine("GetResult");
+await GetResult(managementClient);
+
+return;
+
+static EventStoreProjectionManagementClient ManagementClient(string connection) {
+ #region createClient
+
+ var settings = EventStoreClientSettings.Create(connection);
+ settings.ConnectionName = "Projection management client";
+ settings.DefaultCredentials = new UserCredentials("admin", "changeit");
+ var managementClient = new EventStoreProjectionManagementClient(settings);
+
+ #endregion createClient
+
+ return managementClient;
+}
+
+static async Task RestartSubSystem(EventStoreProjectionManagementClient managementClient) {
+ #region RestartSubSystem
+
+ await managementClient.RestartSubsystemAsync();
+
+ #endregion RestartSubSystem
+}
+
+static async Task Disable(EventStoreProjectionManagementClient managementClient) {
+ #region Disable
+
+ await managementClient.DisableAsync("$by_category");
+
+ #endregion Disable
+}
+
+static async Task DisableNotFound(EventStoreProjectionManagementClient managementClient) {
+ #region DisableNotFound
+
+ try {
+ await managementClient.DisableAsync("projection that does not exists");
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
+ Console.WriteLine(e.Message);
+ }
+
+ #endregion DisableNotFound
+}
+
+static async Task Enable(EventStoreProjectionManagementClient managementClient) {
+ #region Enable
+
+ await managementClient.EnableAsync("$by_category");
+
+ #endregion Enable
+}
+
+static async Task EnableNotFound(EventStoreProjectionManagementClient managementClient) {
+ #region EnableNotFound
+
+ try {
+ await managementClient.EnableAsync("projection that does not exists");
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
+ Console.WriteLine(e.Message);
+ }
+
+ #endregion EnableNotFound
+}
+
+static Task Delete(EventStoreProjectionManagementClient managementClient) {
+ #region Delete
+
+ // this is not yet available in the .net grpc client
+
+ #endregion Delete
+
+ return Task.CompletedTask;
+}
+
+static async Task Abort(EventStoreProjectionManagementClient managementClient) {
+ try {
+ var js =
+ "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
+
+ await managementClient.CreateContinuousAsync("countEvents_Abort", js);
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.Aborted) {
+ // ignore was already created in a previous run
+ }
+ catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
+ // ignore was already created in a previous run
+ }
+
+ #region Abort
+
+ // The .net clients prior to version 21.6 had an incorrect behavior: they will save the checkpoint.
+ await managementClient.AbortAsync("countEvents_Abort");
+
+ #endregion Abort
+}
+
+static async Task Abort_NotFound(EventStoreProjectionManagementClient managementClient) {
+ #region Abort_NotFound
+
+ try {
+ await managementClient.AbortAsync("projection that does not exists");
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
+ Console.WriteLine(e.Message);
+ }
+
+ #endregion Abort_NotFound
+}
+
+static async Task Reset(EventStoreProjectionManagementClient managementClient) {
+ try {
+ var js =
+ "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
+
+ await managementClient.CreateContinuousAsync("countEvents_Reset", js);
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.Internal) {
+ // ignore was already created in a previous run
+ }
+ catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
+ // ignore was already created in a previous run
+ }
+
+ #region Reset
+
+ // Checkpoint will be written prior to resetting the projection
+ await managementClient.ResetAsync("countEvents_Reset");
+
+ #endregion Reset
+}
+
+static async Task Reset_NotFound(EventStoreProjectionManagementClient managementClient) {
+ #region Reset_NotFound
+
+ try {
+ await managementClient.ResetAsync("projection that does not exists");
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
+ Console.WriteLine(e.Message);
+ }
+
+ #endregion Reset_NotFound
+}
+
+static async Task CreateOneTime(EventStoreProjectionManagementClient managementClient) {
+ const string js =
+ "fromAll() .when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
+
+ await managementClient.CreateOneTimeAsync(js);
+}
+
+static async Task CreateContinuous(EventStoreProjectionManagementClient managementClient) {
+ #region CreateContinuous
+
+ const string js = @"fromAll()
.when({
$init: function() {
return {
@@ -214,14 +241,15 @@ private static async Task CreateContinuous(EventStoreProjectionManagementClient
}
})
.outputState();";
- var name = $"countEvents_Create_{Guid.NewGuid()}";
- await managementClient.CreateContinuousAsync(name, js);
- #endregion CreateContinuous
- }
- private static async Task CreateContinuous_Conflict(EventStoreProjectionManagementClient managementClient) {
+ var name = $"countEvents_Create_{Guid.NewGuid()}";
+ await managementClient.CreateContinuousAsync(name, js);
- const string js = @"fromAll()
+ #endregion CreateContinuous
+}
+
+static async Task CreateContinuous_Conflict(EventStoreProjectionManagementClient managementClient) {
+ const string js = @"fromAll()
.when({
$init: function() {
return {
@@ -233,25 +261,30 @@ private static async Task CreateContinuous_Conflict(EventStoreProjectionManageme
}
})
.outputState();";
- var name = $"countEvents_Create_{Guid.NewGuid()}";
-
- #region CreateContinuous_Conflict
- await managementClient.CreateContinuousAsync(name, js);
- try {
-
- await managementClient.CreateContinuousAsync(name, js);
- } catch (RpcException e) when (e.StatusCode is StatusCode.AlreadyExists) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
- var format = $"{name} already exists";
- Console.WriteLine(format);
- }
- #endregion CreateContinuous_Conflict
- }
-
- private static async Task Update(EventStoreProjectionManagementClient managementClient) {
- #region Update
- const string js = @"fromAll()
+
+ var name = $"countEvents_Create_{Guid.NewGuid()}";
+
+ #region CreateContinuous_Conflict
+
+ await managementClient.CreateContinuousAsync(name, js);
+ try {
+ await managementClient.CreateContinuousAsync(name, js);
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.AlreadyExists) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release
+ var format = $"{name} already exists";
+ Console.WriteLine(format);
+ }
+
+ #endregion CreateContinuous_Conflict
+}
+
+static async Task Update(EventStoreProjectionManagementClient managementClient) {
+ #region Update
+
+ const string js = @"fromAll()
.when({
$init: function() {
return {
@@ -263,92 +296,107 @@ private static async Task Update(EventStoreProjectionManagementClient management
}
})
.outputState();";
- var name = $"countEvents_Update_{Guid.NewGuid()}";
-
- await managementClient.CreateContinuousAsync(name, "fromAll().when()");
- await managementClient.UpdateAsync(name, js);
- #endregion Update
- }
-
- private static async Task Update_NotFound(EventStoreProjectionManagementClient managementClient) {
- #region Update_NotFound
- try {
- await managementClient.UpdateAsync("Update Not existing projection", "fromAll().when()");
- } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
- Console.WriteLine(e.Message);
- } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
- Console.WriteLine("'Update Not existing projection' does not exists and can not be updated");
- }
- #endregion Update_NotFound
- }
-
- private static async Task ListAll(EventStoreProjectionManagementClient managementClient) {
- #region ListAll
- var details = managementClient.ListAllAsync();
- await foreach (var detail in details) {
- Console.WriteLine(
- $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}");
- }
- #endregion ListAll
- }
-
- private static async Task ListContinuous(EventStoreProjectionManagementClient managementClient) {
- #region ListContinuous
- var details = managementClient.ListContinuousAsync();
- await foreach (var detail in details) {
- Console.WriteLine(
- $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}");
- }
- #endregion ListContinuous
-
- }
-
- private static async Task GetStatus(EventStoreProjectionManagementClient managementClient) {
- const string js =
- "fromAll().when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
- var name = $"countEvents_status_{Guid.NewGuid()}";
-
- #region GetStatus
- await managementClient.CreateContinuousAsync(name, js);
- var status = await managementClient.GetStatusAsync(name);
- Console.WriteLine(
- $@"{status?.Name}, {status?.Status}, {status?.CheckpointStatus}, {status?.Mode}, {status?.Progress}");
- #endregion GetStatus
- }
-
- private static async Task GetState(EventStoreProjectionManagementClient managementClient) {
-
- // will have to wait for the client to be fixed before we import in the doc
-
- #region GetState
- const string js =
- "fromAll().when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
- var name = $"countEvents_State_{Guid.NewGuid()}";
-
- await managementClient.CreateContinuousAsync(name, js);
- //give it some time to process and have a state.
- await Task.Delay(500);
-
- var stateDocument = await managementClient.GetStateAsync(name);
- var result = await managementClient.GetStateAsync(name);
-
- Console.WriteLine(DocToString(stateDocument));
- Console.WriteLine(result);
-
- static async Task DocToString(JsonDocument d) {
- await using var stream = new MemoryStream();
- Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false });
- d.WriteTo(writer);
- await writer.FlushAsync();
- return Encoding.UTF8.GetString(stream.ToArray());
- }
- #endregion GetState
- }
-
- private static async Task GetResult(EventStoreProjectionManagementClient managementClient) {
-
- #region GetResult
- const string js = @"fromAll()
+
+ var name = $"countEvents_Update_{Guid.NewGuid()}";
+
+ await managementClient.CreateContinuousAsync(name, "fromAll().when()");
+ await managementClient.UpdateAsync(name, js);
+
+ #endregion Update
+}
+
+static async Task Update_NotFound(EventStoreProjectionManagementClient managementClient) {
+ #region Update_NotFound
+
+ try {
+ await managementClient.UpdateAsync("Update Not existing projection", "fromAll().when()");
+ }
+ catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) {
+ Console.WriteLine(e.Message);
+ }
+ catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release
+ Console.WriteLine("'Update Not existing projection' does not exists and can not be updated");
+ }
+
+ #endregion Update_NotFound
+}
+
+static async Task ListAll(EventStoreProjectionManagementClient managementClient) {
+ #region ListAll
+
+ var details = managementClient.ListAllAsync();
+ await foreach (var detail in details)
+ Console.WriteLine(
+ $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}"
+ );
+
+ #endregion ListAll
+}
+
+static async Task ListContinuous(EventStoreProjectionManagementClient managementClient) {
+ #region ListContinuous
+
+ var details = managementClient.ListContinuousAsync();
+ await foreach (var detail in details)
+ Console.WriteLine(
+ $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}"
+ );
+
+ #endregion ListContinuous
+}
+
+static async Task GetStatus(EventStoreProjectionManagementClient managementClient) {
+ const string js =
+ "fromAll().when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
+
+ var name = $"countEvents_status_{Guid.NewGuid()}";
+
+ #region GetStatus
+
+ await managementClient.CreateContinuousAsync(name, js);
+ var status = await managementClient.GetStatusAsync(name);
+ Console.WriteLine(
+ $@"{status?.Name}, {status?.Status}, {status?.CheckpointStatus}, {status?.Mode}, {status?.Progress}"
+ );
+
+ #endregion GetStatus
+}
+
+static async Task GetState(EventStoreProjectionManagementClient managementClient) {
+ // will have to wait for the client to be fixed before we import in the doc
+
+ #region GetState
+
+ const string js =
+ "fromAll().when({$init:function(){return {count:0};},$any:function(s, e){s.count += 1;}}).outputState();";
+
+ var name = $"countEvents_State_{Guid.NewGuid()}";
+
+ await managementClient.CreateContinuousAsync(name, js);
+ //give it some time to process and have a state.
+ await Task.Delay(500);
+
+ var stateDocument = await managementClient.GetStateAsync(name);
+ var result = await managementClient.GetStateAsync(name);
+
+ Console.WriteLine(DocToString(stateDocument));
+ Console.WriteLine(result);
+
+ static async Task DocToString(JsonDocument d) {
+ await using var stream = new MemoryStream();
+ var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false });
+ d.WriteTo(writer);
+ await writer.FlushAsync();
+ return Encoding.UTF8.GetString(stream.ToArray());
+ }
+
+ #endregion GetState
+}
+
+static async Task GetResult(EventStoreProjectionManagementClient managementClient) {
+ #region GetResult
+
+ const string js = @"fromAll()
.when({
$init: function() {
return {
@@ -360,43 +408,48 @@ private static async Task GetResult(EventStoreProjectionManagementClient managem
}
})
.outputState();";
- var name = $"countEvents_Result_{Guid.NewGuid()}";
-
- await managementClient.CreateContinuousAsync(name, js);
- await Task.Delay(500); //give it some time to have a result.
-
- // Results are retrieved either as JsonDocument or a typed result
- var document = await managementClient.GetResultAsync(name);
- var result = await managementClient.GetResultAsync(name);
-
- Console.WriteLine(DocToString(document));
- Console.WriteLine(result);
-
- static string DocToString(JsonDocument d) {
- using var stream = new MemoryStream();
- using Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false });
- d.WriteTo(writer);
- writer.Flush();
- return Encoding.UTF8.GetString(stream.ToArray());
- }
- #endregion GetResult
- }
-
- public class Result {
- public int count { get; set; }
- public override string ToString() => $"count= {count}";
- };
-
- private static async Task Populate(string connection, int numberOfEvents) {
- var settings = EventStoreClientSettings.Create(connection);
- settings.DefaultCredentials = new UserCredentials("admin", "changeit");
- var client = new EventStoreClient(settings);
- var messages = Enumerable.Range(0, numberOfEvents).Select(number =>
- new EventData(Uuid.NewUuid(),
- "eventtype",
- Encoding.UTF8.GetBytes($@"{{ ""Id"":{number} }}"))
- );
- await client.AppendToStreamAsync("sample", StreamState.Any, messages);
- }
+
+ var name = $"countEvents_Result_{Guid.NewGuid()}";
+
+ await managementClient.CreateContinuousAsync(name, js);
+ await Task.Delay(500); //give it some time to have a result.
+
+ // Results are retrieved either as JsonDocument or a typed result
+ var document = await managementClient.GetResultAsync(name);
+ var result = await managementClient.GetResultAsync(name);
+
+ Console.WriteLine(DocToString(document));
+ Console.WriteLine(result);
+
+ static string DocToString(JsonDocument d) {
+ using var stream = new MemoryStream();
+ using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false });
+ d.WriteTo(writer);
+ writer.Flush();
+ return Encoding.UTF8.GetString(stream.ToArray());
}
+
+ #endregion GetResult
}
+
+static async Task Populate(string connection, int numberOfEvents) {
+ var settings = EventStoreClientSettings.Create(connection);
+ settings.DefaultCredentials = new UserCredentials("admin", "changeit");
+ var client = new EventStoreClient(settings);
+ var messages = Enumerable.Range(0, numberOfEvents).Select(
+ number =>
+ new EventData(
+ Uuid.NewUuid(),
+ "eventtype",
+ Encoding.UTF8.GetBytes($@"{{ ""Id"":{number} }}")
+ )
+ );
+
+ await client.AppendToStreamAsync("sample", StreamState.Any, messages);
+}
+
+public class Result {
+ public int count { get; set; }
+
+ public override string ToString() => $"count= {count}";
+};
\ No newline at end of file
diff --git a/samples/quick-start/Program.cs b/samples/quick-start/Program.cs
index e79b524d9..0cd070137 100644
--- a/samples/quick-start/Program.cs
+++ b/samples/quick-start/Program.cs
@@ -1,77 +1,70 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.Http;
-using System.Net.Security;
-using System.Security.Cryptography.X509Certificates;
-using System.Text;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using EventStore.Client;
-
-namespace quick_start {
- public class TestEvent {
- public string? EntityId { get; set; }
- public string? ImportantData { get; set; }
- }
-
- class Program {
- static void Main(string[] args) {
- }
-
- static async Task Samples() {
- CancellationTokenSource tokenSource = new CancellationTokenSource();
- CancellationToken cancellationToken = tokenSource.Token;
-
- #region createClient
- var settings = EventStoreClientSettings
- .Create("{connectionString}");
- var client = new EventStoreClient(settings);
- #endregion createClient
-
- #region createEvent
- var evt = new TestEvent
- {
- EntityId = Guid.NewGuid().ToString("N"),
- ImportantData = "I wrote my first event!"
- };
-
- var eventData = new EventData(
- Uuid.NewUuid(),
- "TestEvent",
- JsonSerializer.SerializeToUtf8Bytes(evt)
- );
- #endregion createEvent
-
- #region appendEvents
- await client.AppendToStreamAsync(
- "some-stream",
- StreamState.Any,
- new[] { eventData },
- cancellationToken: cancellationToken
- );
- #endregion appendEvents
-
- #region overriding-user-credentials
- await client.AppendToStreamAsync(
- "some-stream",
- StreamState.Any,
- new[] { eventData },
- userCredentials: new UserCredentials("admin", "changeit"),
- cancellationToken: cancellationToken
- );
- #endregion overriding-user-credentials
-
- #region readStream
- var result = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- StreamPosition.Start,
- cancellationToken: cancellationToken);
-
- var events = await result.ToListAsync(cancellationToken);
- #endregion readStream
- }
- }
-}
+using System.Text.Json;
+
+var tokenSource = new CancellationTokenSource();
+var cancellationToken = tokenSource.Token;
+
+#region createClient
+
+const string connectionString = "esdb://admin:changeit@localhost:2113?tls=false&tlsVerifyCert=false";
+
+var settings = EventStoreClientSettings.Create(connectionString);
+
+var client = new EventStoreClient(settings);
+
+#endregion createClient
+
+#region createEvent
+
+var evt = new TestEvent {
+ EntityId = Guid.NewGuid().ToString("N"),
+ ImportantData = "I wrote my first event!"
+};
+
+var eventData = new EventData(
+ Uuid.NewUuid(),
+ "TestEvent",
+ JsonSerializer.SerializeToUtf8Bytes(evt)
+);
+
+#endregion createEvent
+
+#region appendEvents
+
+await client.AppendToStreamAsync(
+ "some-stream",
+ StreamState.Any,
+ new[] { eventData },
+ cancellationToken: cancellationToken
+);
+
+#endregion appendEvents
+
+#region overriding-user-credentials
+
+await client.AppendToStreamAsync(
+ "some-stream",
+ StreamState.Any,
+ new[] { eventData },
+ userCredentials: new UserCredentials("admin", "changeit"),
+ cancellationToken: cancellationToken
+);
+
+#endregion overriding-user-credentials
+
+#region readStream
+
+var result = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ StreamPosition.Start,
+ cancellationToken: cancellationToken
+);
+
+var events = await result.ToListAsync(cancellationToken);
+
+#endregion readStream
+
+public class TestEvent {
+ public string? EntityId { get; set; }
+ public string? ImportantData { get; set; }
+}
\ No newline at end of file
diff --git a/samples/quick-start/docker-compose.yml b/samples/quick-start/docker-compose.yml
index 9001ea312..f6621fd78 100644
--- a/samples/quick-start/docker-compose.yml
+++ b/samples/quick-start/docker-compose.yml
@@ -1,9 +1,12 @@
-version: '3'
+version: '3.5'
services:
eventstore:
- image: eventstore/eventstore:20.10.0-buster-slim
+ image: eventstore/eventstore:latest
environment:
- - EVENTSTORE_INSECURE=true
- - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
+ EVENTSTORE_INSECURE: true
+ EVENTSTORE_MEM_DB: false
+ EVENTSTORE_RUN_PROJECTIONS: all
+ EVENTSTORE_START_STANDARD_PROJECTIONS: true
+ EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: true
ports:
- - 2113:2113
+ - "2113:2113"
\ No newline at end of file
diff --git a/samples/quick-start/quick-start.csproj b/samples/quick-start/quick-start.csproj
index 9921046d6..b33948026 100644
--- a/samples/quick-start/quick-start.csproj
+++ b/samples/quick-start/quick-start.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/samples/reading-events/Program.cs b/samples/reading-events/Program.cs
index c09c64238..854634da8 100644
--- a/samples/reading-events/Program.cs
+++ b/samples/reading-events/Program.cs
@@ -1,295 +1,321 @@
-using System;
-using System.Linq;
-using System.Net.Http;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using EventStore.Client;
-
-namespace reading_events {
- class Program {
- static async Task Main(string[] args) {
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://localhost:2113?tls=false")
- );
-
- var events = Enumerable.Range(0, 20)
- .Select(r => new EventData(
- Uuid.NewUuid(),
- "some-event",
- Encoding.UTF8.GetBytes("{\"id\": \"" + r + "\" \"value\": \"some value\"}")));
-
- await client.AppendToStreamAsync(
- "some-stream",
- StreamState.Any,
- events);
-
- await ReadFromStream(client);
-
- return;
- }
+#pragma warning disable CS8321 // Local function is declared but never used
- private static async Task ReadFromStream(EventStoreClient client) {
- #region read-from-stream
- var events = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- StreamPosition.Start);
- #endregion read-from-stream
-
- #region iterate-stream
- await foreach (var @event in events) {
- Console.WriteLine(Encoding.UTF8.GetString(@event.Event.Data.ToArray()));
- }
- #endregion iterate-stream
-
- #region #read-from-stream-positions
- Console.WriteLine(events.FirstStreamPosition);
- Console.WriteLine(events.LastStreamPosition);
- #endregion
- }
+await using var client = new EventStoreClient(EventStoreClientSettings.Create("esdb://localhost:2113?tls=false"));
- private static async Task ReadFromStreamMessages(EventStoreClient client) {
- #region read-from-stream-messages
- var streamPosition = StreamPosition.Start;
- var results = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- streamPosition);
- #endregion read-from-stream-messages
-
- #region iterate-stream-messages
- await foreach (var message in results.Messages) {
- switch (message) {
- case StreamMessage.Ok ok:
- Console.WriteLine("Stream found.");
- break;
- case StreamMessage.NotFound:
- Console.WriteLine("Stream not found.");
- return;
- case StreamMessage.Event(var resolvedEvent):
- Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
- break;
- case StreamMessage.FirstStreamPosition(var sp):
- Console.WriteLine($"{sp} is after {streamPosition}; updating checkpoint.");
- streamPosition = sp;
- break;
- case StreamMessage.LastStreamPosition(var sp):
- Console.WriteLine($"The end of the stream is {sp}");
- break;
- default:
- break;
- }
- }
- #endregion iterate-stream-messages
- }
+var events = Enumerable.Range(0, 20)
+ .Select(
+ r => new EventData(
+ Uuid.NewUuid(),
+ "some-event",
+ Encoding.UTF8.GetBytes($"{{\"id\": \"{r}\" \"value\": \"some value\"}}")
+ )
+ );
- private static async Task ReadFromStreamPosition(EventStoreClient client) {
- #region read-from-stream-position
- var events = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- revision: 10,
- maxCount: 20);
- #endregion read-from-stream-position
-
- #region iterate-stream
- await foreach (var @event in events) {
- Console.WriteLine(Encoding.UTF8.GetString(@event.Event.Data.ToArray()));
- }
- #endregion iterate-stream
- }
+await client.AppendToStreamAsync(
+ "some-stream",
+ StreamState.Any,
+ events
+);
+
+await ReadFromStream(client);
+
+return;
+
+static async Task ReadFromStream(EventStoreClient client) {
+ #region read-from-stream
+
+ var events = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ StreamPosition.Start
+ );
+
+ #endregion read-from-stream
+
+ #region iterate-stream
+
+ await foreach (var @event in events) Console.WriteLine(Encoding.UTF8.GetString(@event.Event.Data.ToArray()));
+
+ #endregion iterate-stream
+
+ #region #read-from-stream-positions
- private static async Task ReadFromStreamPositionCheck(EventStoreClient client) {
- #region checking-for-stream-presence
- var result = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- revision: 10,
- maxCount: 20);
+ Console.WriteLine(events.FirstStreamPosition);
+ Console.WriteLine(events.LastStreamPosition);
- if (await result.ReadState == ReadState.StreamNotFound) {
+ #endregion
+}
+
+static async Task ReadFromStreamMessages(EventStoreClient client) {
+ #region read-from-stream-messages
+
+ var streamPosition = StreamPosition.Start;
+ var results = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ streamPosition
+ );
+
+ #endregion read-from-stream-messages
+
+ #region iterate-stream-messages
+
+ await foreach (var message in results.Messages)
+ switch (message) {
+ case StreamMessage.Ok ok:
+ Console.WriteLine("Stream found.");
+ break;
+
+ case StreamMessage.NotFound:
+ Console.WriteLine("Stream not found.");
return;
- }
- await foreach (var e in result) {
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- #endregion checking-for-stream-presence
- }
+ case StreamMessage.Event(var resolvedEvent):
+ Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
+ break;
- private static async Task ReadFromStreamBackwards(EventStoreClient client) {
- #region reading-backwards
- var events = client.ReadStreamAsync(
- Direction.Backwards,
- "some-stream",
- StreamPosition.End);
-
- await foreach (var e in events) {
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- #endregion reading-backwards
- }
+ case StreamMessage.FirstStreamPosition(var sp):
+ Console.WriteLine($"{sp} is after {streamPosition}; updating checkpoint.");
+ streamPosition = sp;
+ break;
- private static async Task ReadFromStreamMessagesBackwards(EventStoreClient client) {
- #region read-from-stream-messages-backwards
- var results = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- StreamPosition.End);
- #endregion read-from-stream-messages-backwards
-
- #region iterate-stream-messages-backwards
- await foreach (var message in results.Messages) {
- switch (message) {
- case StreamMessage.Ok ok:
- Console.WriteLine("Stream found.");
- break;
- case StreamMessage.NotFound:
- Console.WriteLine("Stream not found.");
- return;
- case StreamMessage.Event(var resolvedEvent):
- Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
- break;
- case StreamMessage.LastStreamPosition(var sp):
- Console.WriteLine($"The end of the stream is {sp}");
- break;
- }
- }
- #endregion iterate-stream-messages-backwards
+ case StreamMessage.LastStreamPosition(var sp):
+ Console.WriteLine($"The end of the stream is {sp}");
+ break;
+
+ default:
+ break;
}
+ #endregion iterate-stream-messages
+}
- private static async Task ReadFromAllStream(EventStoreClient client) {
- #region read-from-all-stream
- var events = client.ReadAllAsync(
- Direction.Forwards, Position.Start);
- #endregion read-from-all-stream
+static async Task ReadFromStreamPosition(EventStoreClient client) {
+ #region read-from-stream-position
- #region read-from-all-stream-iterate
- await foreach (var e in events) {
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- #endregion read-from-all-stream-iterate
- }
+ var events = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ 10,
+ 20
+ );
- private static async Task ReadFromAllStreamMessages(EventStoreClient client) {
- #region read-from-all-stream-messages
- var position = Position.Start;
- var results = client.ReadAllAsync(
- Direction.Forwards,
- position: position);
- #endregion read-from-all-stream-messages
-
- #region iterate-all-stream-messages
- await foreach (var message in results.Messages) {
- switch (message) {
- case StreamMessage.Event(var resolvedEvent):
- Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
- break;
- case StreamMessage.LastAllStreamPosition(var p):
- Console.WriteLine($"The end of the $all stream is {p}");
- break;
- }
- }
- #endregion iterate-all-stream-messages
- }
+ #endregion read-from-stream-position
- private static async Task IgnoreSystemEvents(EventStoreClient client) {
- #region ignore-system-events
- var events = client.ReadAllAsync(
- Direction.Forwards, Position.Start);
+ #region iterate-stream
- await foreach (var e in events) {
- if (e.Event.EventType.StartsWith("$")) {
- continue;
- }
+ await foreach (var @event in events) Console.WriteLine(Encoding.UTF8.GetString(@event.Event.Data.ToArray()));
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- #endregion ignore-system-events
- }
+ #endregion iterate-stream
+}
- private static async Task ReadFromAllStreamBackwards(EventStoreClient client) {
- #region read-from-all-stream-backwards
- var events = client.ReadAllAsync(
- Direction.Backwards, Position.End);
- #endregion read-from-all-stream-backwards
-
- #region read-from-all-stream-iterate
- await foreach (var e in events) {
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- #endregion read-from-all-stream-iterate
- }
+static async Task ReadFromStreamPositionCheck(EventStoreClient client) {
+ #region checking-for-stream-presence
- private static async Task ReadFromAllStreamBackwardsMessages(EventStoreClient client) {
- #region read-from-all-stream-messages-backwards
- var position = Position.End;
- var results = client.ReadAllAsync(
- Direction.Backwards,
- position: position);
- #endregion read-from-all-stream-messages-backwards
-
- #region iterate-all-stream-messages-backwards
- await foreach (var message in results.Messages) {
- switch (message) {
- case StreamMessage.Event(var resolvedEvent):
- Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
- break;
- case StreamMessage.LastAllStreamPosition(var p):
- Console.WriteLine($"{p} is before {position}; updating checkpoint.");
- position = p;
- break;
- }
- }
- #endregion iterate-all-stream-messages-backwards
- }
+ var result = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ 10,
+ 20
+ );
- private static async Task FilteringOutSystemEvents(EventStoreClient client) {
- var events = client.ReadAllAsync(Direction.Forwards, Position.Start);
+ if (await result.ReadState == ReadState.StreamNotFound) return;
- await foreach (var e in events) {
- if (!e.Event.EventType.StartsWith("$")) {
- Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- }
- }
- }
+ await foreach (var e in result) Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
- private void ReadStreamOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken)
- {
- #region overriding-user-credentials
- var result = client.ReadStreamAsync(
- Direction.Forwards,
- "some-stream",
- StreamPosition.Start,
- userCredentials: new UserCredentials("admin", "changeit"),
- cancellationToken: cancellationToken);
- #endregion overriding-user-credentials
- }
+ #endregion checking-for-stream-presence
+}
+
+static async Task ReadFromStreamBackwards(EventStoreClient client) {
+ #region reading-backwards
+
+ var events = client.ReadStreamAsync(
+ Direction.Backwards,
+ "some-stream",
+ StreamPosition.End
+ );
+
+ await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
+
+ #endregion reading-backwards
+}
+
+static async Task ReadFromStreamMessagesBackwards(EventStoreClient client) {
+ #region read-from-stream-messages-backwards
+
+ var results = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ StreamPosition.End
+ );
+
+ #endregion read-from-stream-messages-backwards
+
+ #region iterate-stream-messages-backwards
+
+ await foreach (var message in results.Messages)
+ switch (message) {
+ case StreamMessage.Ok ok:
+ Console.WriteLine("Stream found.");
+ break;
- private void ReadAllOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken)
- {
- #region read-all-overriding-user-credentials
- var result = client.ReadAllAsync(
- Direction.Forwards,
- Position.Start,
- userCredentials: new UserCredentials("admin", "changeit"),
- cancellationToken: cancellationToken);
- #endregion read-all-overriding-user-credentials
+ case StreamMessage.NotFound:
+ Console.WriteLine("Stream not found.");
+ return;
+
+ case StreamMessage.Event(var resolvedEvent):
+ Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
+ break;
+
+ case StreamMessage.LastStreamPosition(var sp):
+ Console.WriteLine($"The end of the stream is {sp}");
+ break;
}
-
-
- private void ReadAllResolvingLinkTos(EventStoreClient client, CancellationToken cancellationToken)
- {
- #region read-from-all-stream-resolving-link-Tos
- var result = client.ReadAllAsync(
- Direction.Forwards,
- Position.Start,
- resolveLinkTos: true,
- cancellationToken: cancellationToken);
- #endregion read-from-all-stream-resolving-link-Tos
+
+ #endregion iterate-stream-messages-backwards
+}
+
+static async Task ReadFromAllStream(EventStoreClient client) {
+ #region read-from-all-stream
+
+ var events = client.ReadAllAsync(Direction.Forwards, Position.Start);
+
+ #endregion read-from-all-stream
+
+ #region read-from-all-stream-iterate
+
+ await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
+
+ #endregion read-from-all-stream-iterate
+}
+
+static async Task ReadFromAllStreamMessages(EventStoreClient client) {
+ #region read-from-all-stream-messages
+
+ var position = Position.Start;
+ var results = client.ReadAllAsync(
+ Direction.Forwards,
+ position
+ );
+
+ #endregion read-from-all-stream-messages
+
+ #region iterate-all-stream-messages
+
+ await foreach (var message in results.Messages)
+ switch (message) {
+ case StreamMessage.Event(var resolvedEvent):
+ Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
+ break;
+
+ case StreamMessage.LastAllStreamPosition(var p):
+ Console.WriteLine($"The end of the $all stream is {p}");
+ break;
}
+
+ #endregion iterate-all-stream-messages
+}
+
+static async Task IgnoreSystemEvents(EventStoreClient client) {
+ #region ignore-system-events
+
+ var events = client.ReadAllAsync(Direction.Forwards, Position.Start);
+
+ await foreach (var e in events) {
+ if (e.Event.EventType.StartsWith("$")) continue;
+
+ Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
}
+
+ #endregion ignore-system-events
}
+
+static async Task ReadFromAllStreamBackwards(EventStoreClient client) {
+ #region read-from-all-stream-backwards
+
+ var events = client.ReadAllAsync(Direction.Backwards, Position.End);
+
+ #endregion read-from-all-stream-backwards
+
+ #region read-from-all-stream-iterate
+
+ await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
+
+ #endregion read-from-all-stream-iterate
+}
+
+static async Task ReadFromAllStreamBackwardsMessages(EventStoreClient client) {
+ #region read-from-all-stream-messages-backwards
+
+ var position = Position.End;
+ var results = client.ReadAllAsync(
+ Direction.Backwards,
+ position
+ );
+
+ #endregion read-from-all-stream-messages-backwards
+
+ #region iterate-all-stream-messages-backwards
+
+ await foreach (var message in results.Messages)
+ switch (message) {
+ case StreamMessage.Event(var resolvedEvent):
+ Console.WriteLine(Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span));
+ break;
+
+ case StreamMessage.LastAllStreamPosition(var p):
+ Console.WriteLine($"{p} is before {position}; updating checkpoint.");
+ position = p;
+ break;
+ }
+
+ #endregion iterate-all-stream-messages-backwards
+}
+
+static async Task FilteringOutSystemEvents(EventStoreClient client) {
+ var events = client.ReadAllAsync(Direction.Forwards, Position.Start);
+
+ await foreach (var e in events)
+ if (!e.Event.EventType.StartsWith("$"))
+ Console.WriteLine(Encoding.UTF8.GetString(e.Event.Data.ToArray()));
+}
+
+static void ReadStreamOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken) {
+ #region overriding-user-credentials
+
+ var result = client.ReadStreamAsync(
+ Direction.Forwards,
+ "some-stream",
+ StreamPosition.Start,
+ userCredentials: new UserCredentials("admin", "changeit"),
+ cancellationToken: cancellationToken
+ );
+
+ #endregion overriding-user-credentials
+}
+
+static void ReadAllOverridingUserCredentials(EventStoreClient client, CancellationToken cancellationToken) {
+ #region read-all-overriding-user-credentials
+
+ var result = client.ReadAllAsync(
+ Direction.Forwards,
+ Position.Start,
+ userCredentials: new UserCredentials("admin", "changeit"),
+ cancellationToken: cancellationToken
+ );
+
+ #endregion read-all-overriding-user-credentials
+}
+
+static void ReadAllResolvingLinkTos(EventStoreClient client, CancellationToken cancellationToken) {
+ #region read-from-all-stream-resolving-link-Tos
+
+ var result = client.ReadAllAsync(
+ Direction.Forwards,
+ Position.Start,
+ resolveLinkTos: true,
+ cancellationToken: cancellationToken
+ );
+
+ #endregion read-from-all-stream-resolving-link-Tos
+}
\ No newline at end of file
diff --git a/samples/reading-events/reading-events.csproj b/samples/reading-events/reading-events.csproj
index 0ae95a9a5..436254ea7 100644
--- a/samples/reading-events/reading-events.csproj
+++ b/samples/reading-events/reading-events.csproj
@@ -5,7 +5,7 @@
-
+
\ No newline at end of file
diff --git a/samples/secure-with-tls/.dockerignore b/samples/secure-with-tls/.dockerignore
index cf69769bd..cd967fc3a 100644
--- a/samples/secure-with-tls/.dockerignore
+++ b/samples/secure-with-tls/.dockerignore
@@ -1,4 +1,25 @@
-**/bin/
-**/obj/
-**/out/
-**/TestResults/
\ No newline at end of file
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.idea
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/samples/secure-with-tls/Dockerfile b/samples/secure-with-tls/Dockerfile
index 5dc195f0d..6e454b881 100644
--- a/samples/secure-with-tls/Dockerfile
+++ b/samples/secure-with-tls/Dockerfile
@@ -1,37 +1,72 @@
-# BUILDER
-FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS builder
+ARG BUILDER_IMG=mcr.microsoft.com/dotnet/sdk:8.0-jammy
+ARG RUNNER_IMG=mcr.microsoft.com/dotnet/runtime:8.0.0-jammy
+ARG APP_NAME="secure-with-tls"
+ARG BUILD_CONFIGURATION=Release
+#---------------------------------------------
+# Prepare runtime image
+#---------------------------------------------
+FROM $RUNNER_IMG AS run
+ARG APP_NAME
+
+# copy pregenerated certificates into usr local CA location
+COPY ./certs/ca/ca.crt /usr/local/share/ca-certificates/eventstoredb_ca.crt
+
+# set permissions
+RUN chmod 644 /usr/local/share/ca-certificates/eventstoredb_ca.crt
+
+# install certificates
+RUN update-ca-certificates
+
+# configure entrypoint
WORKDIR /app
+ENV ENTRYPOINT "dotnet ${APP_NAME}.dll"
+ENTRYPOINT $ENTRYPOINT
-# Copy csproj and restore
-COPY ./secure-with-tls.csproj ./
+#---------------------------------------------
+# Build application
+#---------------------------------------------
+FROM $BUILDER_IMG AS build
+ARG APP_NAME
+ARG BUILD_CONFIGURATION
+
+WORKDIR /src
+
+# copy project file
+COPY ${APP_NAME}.csproj /src/${APP_NAME}/
+
+# helper var
+ENV PROJECT_FILE_PATH=$APP_NAME/$APP_NAME.csproj
# we need comment out project reference and uncomment the package reference
-# If you're using the package reference those lines are not needed
-RUN sed -i 's///' secure-with-tls.csproj && \
- sed -i 's////' $PROJECT_FILE_PATH && \
+ sed -i 's// { eventData }
+ );
+
+ Console.WriteLine($"SUCCESS! Append result: {appendResult.LogPosition}");
+}
+catch (Exception exception) {
+ const string noNodeConnectionErrorMessage = "No connection could be made because the target machine actively refused it.";
+ const string connectionRefused = "Connection refused";
+ const string certificateIsNotInstalledOrInvalidErrorMessage = "The remote certificate is invalid according to the validation procedure.";
+ var innerException = exception.InnerException;
+
+ if (innerException is RpcException rpcException) {
+ if (rpcException.Message.Contains(noNodeConnectionErrorMessage)
+ || rpcException.Message.Contains(connectionRefused)) {
+ Console.WriteLine(
+ $"FAILED! {noNodeConnectionErrorMessage} "
+ + $"Please makes sure that: EventStoreDB node is running, you're using a valid IP "
+ + $"address or DNS name, that port is valid and exposed (forwarded) in node config."
+ );
- try {
- var appendResult = await client.AppendToStreamAsync(
- "some-stream",
- StreamState.Any,
- new List {
- eventData
- });
- Console.WriteLine($"SUCCESS! Append result: {appendResult.LogPosition}");
- }
- catch (Exception exception)
- {
- var innerException = exception.InnerException;
+ return;
+ }
- if (innerException is RpcException rpcException)
- {
- if (rpcException.Message.Contains(NoNodeConnectionErrorMessage) || rpcException.Message.Contains(ConnectionRefused)) {
- Console.WriteLine(
- $"FAILED! {NoNodeConnectionErrorMessage} Please makes sure that: EventStoreDB node is running, you're using a valid IP address or DNS name, that port is valid and exposed (forwarded) in node config.");
- return;
- }
+ if (rpcException.Message.Contains(certificateIsNotInstalledOrInvalidErrorMessage)) {
+ Console.WriteLine(
+ $"FAILED! {certificateIsNotInstalledOrInvalidErrorMessage} "
+ + $"Please makes sure that you installed CA certificate on client environment "
+ + $"and that it was generated with IP address or DNS name used for connecting."
+ );
- if (rpcException.Message.Contains(CertificateIsNotInstalledOrInvalidErrorMessage))
- {
- Console.WriteLine(
- $"FAILED! {CertificateIsNotInstalledOrInvalidErrorMessage} Please makes sure that you installed CA certificate on client environment and that it was generated with IP address or DNS name used for connecting.");
- return;
- }
- }
- Console.WriteLine($"FAILED! {exception}");
- }
+ return;
}
}
-}
+
+ Console.WriteLine($"FAILED! {exception}");
+}
\ No newline at end of file
diff --git a/samples/secure-with-tls/README.md b/samples/secure-with-tls/README.md
index 01f7f96d4..74da47d62 100644
--- a/samples/secure-with-tls/README.md
+++ b/samples/secure-with-tls/README.md
@@ -8,14 +8,14 @@
- [1. Generate self-signed certificates](#1-generate-self-signed-certificates)
- [2. Run samples with Docker](#2-run-samples-with-docker)
- [3. Run samples locally (without Docker)](#3-run-samples-locally-without-docker)
- - [3.1 Install certificate - Linux (Ubuntu, Debian)](#31-install-certificate---linux-ubuntu-debian)
+ - [3.1 Install certificate - Linux (Ubuntu, Debian, WSL) or MacOS](#31-install-certificate---linux-ubuntu-debian)
- [3.2 Install certificate - Windows](#32-install-certificate---windows)
- - [3.3. Run EventStoreDB node](#33-run-eventstoredb-node)
+ - [3.3 Run EventStoreDB node](#33-run-eventstoredb-node)
- [3.3 Run client application](#33-run-client-application)
## Overview
-The sample shows how to run the .NET gRPC client secured by TLS certificates.
+The sample shows how to run the .NET client secured by TLS certificates.
Read more in the docs:
- [Security](https://developers.eventstore.com/server/v20/server/security/)
@@ -23,7 +23,9 @@ Read more in the docs:
- [Event Store Certificate Generation CLI](https://github.com/EventStore/es-gencert-cli)
It is essential for production use to configure EventStoreDB security features to prevent unauthorised access to your data.
-EventStoreDB supports gRPC with TLS and SSL. Each protocol has its security configuration, but you can only use one set of certificates for TLS and HTTPS.
+EventStoreDB supports gRPC with TLS and SSL.
+
+Each protocol has its security configuration, but you can only use one set of certificates for TLS and HTTPS.
### Certificates
@@ -44,45 +46,29 @@ While generating the certificate, you need to remember to pass:
- DNS names to `-dns-names`: e.g. `localhost,eventstoredb`
that will match the URLs that you will be accessing EventStoreDB nodes.
-[Certificate Generation CLI](https://github.com/EventStore/es-gencert-cli) is also available as the Docker image. You can define [docker-compose configuration](./docker-compose.generate-certs.yml) as e.g.:
-
-```yaml
-version: "3.5"
-
-services:
- cert-gen:
- image: eventstore/es-gencert-cli:1.0.2
- entrypoint: bash
- command: >
- -c "es-gencert-cli create-ca -out /tmp/certs/ca &&
- es-gencert-cli create-node -ca-certificate /tmp/certs/ca/ca.crt -ca-key /tmp/certs/ca/ca.key -out \
- /tmp/certs/node -ip-addresses 127.0.0.1 -dns-names localhost,eventstoredb"
- user: "1000:1000"
- volumes:
- - "./certs:/tmp/certs"
-```
-
-And run `docker-compose up` to generate certificates.
+The [Certificate Generation CLI](https://github.com/EventStore/es-gencert-cli) is also available as the Docker image. Check the [docker-compose.certs.yml](./docker-compose.certs.yml)
See instruction how to install certificates [below](#3-run-run-samples-locally-without-docker).
You can find helpers scripts that are also installing created CA on local machine:
-- Linux (Debian based) - [create-certs.sh](./create-certs.sh),
+- Linux (Debian based, MacOS and WSL) - [create-certs.sh](./create-certs.sh),
- Windows - [create-certs.ps1](./create-certs.ps1)
## Description
-The sample shows how to connect with the gRPC client and append new event. You can run it locally or through docker configuration.
+The sample shows how to connect with the client and append new event. You can run it locally or through docker configuration.
Suggested order of reading:
-- whole code is located in [Program.cs](./Program.cs) file
-- [Dockerfile](./Dockerfile) for building sample image
-- [Docker compose config](./docker-compose.yml) that has configuration for both sample client app and EventStoreDB node.
+- The full code is located in [Program.cs](./Program.cs) file
+- [Dockerfile](./Dockerfile) - for building the sample image
+- [docker-compose.yml](./docker-compose.yml) - for running a single EventStoreDB node.
+- [docker-compose.app.yml](./docker-compose.app.yml) - for running the sample client app.
+- [docker-compose.certs.yml](./docker-compose.certs.yml) - for generating certificates.
## Running Sample
### 1. Generate self-signed certificates
-Use following command to generate certificates:
+Use following command to generate and install certificates:
- Linux/MacOS
```console
./create-certs.sh
@@ -91,43 +77,30 @@ Use following command to generate certificates:
```powershell
.\create-certs.ps1
```
+
_Note: to regenerate certificates you need to remove the [./certs](./certs) folder._
### 2. Run samples with Docker
-Use the following command to run samples with Docker:
-```consoler
-docker-compose up
+The following command will run both server and client with preconfigured TLS connection setup.
+
+```console
+docker-compose -f docker-compose.yml -f docker-compose.app.yml up
```
-It will run both server and client with preconfigured TLS connection setup.
### 3. Run samples locally (without Docker)
-To run samples locally, you need to install the generated CA certificate.
-
-#### 3.1 Install certificate - Linux (Ubuntu, Debian)
-- Copy [./certs/ca/ca.crt](./certs/ca/ca.crt) to dir `/usr/local/share/ca-certificates/`
-- Use command:
- ```console
- sudo cp foo.crt /usr/local/share/ca-certificates/foo.crt
- ```
-- Update the CA store:
- ```console
- sudo update-ca-certificates
- ```
-#### 3.2 Install certificate - Windows
-Windows certificate will be automatically installed when [./create-certs.ps1](./create-certs.ps1) was run.
+Assuming the certificates were generated and installed.
-#### 3.3. Run EventStoreDB node
+#### 3.1 Run EventStoreDB
Use the following command to run EventStoreDB
```console
-docker-compose up eventstoredb
+docker-compose up -d
```
-#### 3.3 Run client application
-Run application from console:
+#### 3.2 Run client application
+Run the application from your favourite IDE or the console:
```console
dotnet run ./secure-with-tls.csproj
```
-or from your favourite IDE.
diff --git a/samples/secure-with-tls/create-certs.ps1 b/samples/secure-with-tls/create-certs.ps1
index b53185cda..34fabb178 100644
--- a/samples/secure-with-tls/create-certs.ps1
+++ b/samples/secure-with-tls/create-certs.ps1
@@ -1,5 +1,5 @@
New-Item -ItemType Directory -Force -Path certs
-docker-compose -f docker-compose.generate-certs.yml up
+docker-compose -f docker-compose.certs.yml up --remove-orphans
Import-Certificate -FilePath ".\certs\ca\ca.crt" -CertStoreLocation Cert:\CurrentUser\Root
diff --git a/samples/secure-with-tls/create-certs.sh b/samples/secure-with-tls/create-certs.sh
old mode 100644
new mode 100755
index 2fc0777b2..e51e2a296
--- a/samples/secure-with-tls/create-certs.sh
+++ b/samples/secure-with-tls/create-certs.sh
@@ -1,2 +1,31 @@
+unameOutput="$(uname -sr)"
+case "${unameOutput}" in
+ Linux*Microsoft*) machine=WSL;;
+ Linux*) machine=Linux;;
+ Darwin*) machine=MacOS;;
+ *) machine="${unameOutput}"
+esac
+
+echo ">> Generating certificate..."
mkdir -p certs
-docker-compose -f docker-compose.generate-certs.yml up
+docker-compose -f docker-compose.certs.yml up --remove-orphans
+
+echo ">> Copying certificate..."
+cp certs/ca/ca.crt /usr/local/share/ca-certificates/eventstore_ca.crt
+#rsync --progress certs/ca/ca.crt /usr/local/share/ca-certificates/eventstore_ca.crt
+
+echo ">> Updating certificate permissions..."
+#chmod 644 /usr/local/share/ca-certificates/eventstore_ca.crt
+
+if [ "${machine}" == "MacOS" ]; then
+ echo ">> Installing certificate on ${machine}..."
+ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /usr/local/share/ca-certificates/eventstore_ca.crt
+elif [ "$(machine)" == "Linux" ]; then
+ echo ">> Installing certificate on ${machine}..."
+ sudo update-ca-certificates
+elif [ "$(machine)" == "WSL" ]; then
+ echo ">> Installing certificate on ${machine}..."
+ sudo update-ca-certificates
+else
+ echo ">> Unknown platform. Please install the certificate manually."
+fi
\ No newline at end of file
diff --git a/samples/secure-with-tls/docker-compose.app.yml b/samples/secure-with-tls/docker-compose.app.yml
new file mode 100644
index 000000000..b96f84ae8
--- /dev/null
+++ b/samples/secure-with-tls/docker-compose.app.yml
@@ -0,0 +1,19 @@
+version: "3.5"
+
+networks:
+ default:
+ name: eventstore-network
+
+services:
+
+ app:
+ container_name: app
+ build: ./
+ environment:
+ # URL should match the DNS name in certificate and container name
+ - ESDB__CONNECTION__STRING=esdb://admin:changeit@eventstore:2113?Tls=true&tlsVerifyCert=false
+ depends_on:
+ eventstore:
+ condition: service_healthy
+ links:
+ - eventstore
diff --git a/samples/secure-with-tls/docker-compose.certs.yml b/samples/secure-with-tls/docker-compose.certs.yml
new file mode 100644
index 000000000..56c6278dc
--- /dev/null
+++ b/samples/secure-with-tls/docker-compose.certs.yml
@@ -0,0 +1,30 @@
+version: "3.5"
+
+networks:
+ default:
+ name: eventstore-network
+
+services:
+
+ volumes-provisioner:
+ image: hasnat/volumes-provisioner
+ container_name: volumes-provisioner
+ environment:
+ PROVISION_DIRECTORIES: "1000:1000:0755:/tmp/certs"
+ volumes:
+ - "./certs:/tmp/certs"
+ network_mode: none
+
+ cert-gen:
+ image: eventstore/es-gencert-cli:1.0.2
+ container_name: cert-gen
+ user: "1000:1000"
+ entrypoint: [ "/bin/sh","-c" ]
+ command:
+ - |
+ es-gencert-cli create-ca -out /tmp/certs/ca
+ es-gencert-cli create-node -ca-certificate /tmp/certs/ca/ca.crt -ca-key /tmp/certs/ca/ca.key -out /tmp/certs/node -ip-addresses 127.0.0.1 -dns-names localhost,eventstore
+ volumes:
+ - "./certs:/tmp/certs"
+ depends_on:
+ - volumes-provisioner
diff --git a/samples/secure-with-tls/docker-compose.generate-certs.yml b/samples/secure-with-tls/docker-compose.generate-certs.yml
deleted file mode 100644
index ec62ab85a..000000000
--- a/samples/secure-with-tls/docker-compose.generate-certs.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-version: "3.5"
-
-services:
- cert-gen:
- image: eventstore/es-gencert-cli:1.0.2
- entrypoint: bash
- # dns-name in this case `eventstoredb` matches EventStoreDB container_name and URL it's accessed at `docker-compose.yml`
- command: >
- -c "es-gencert-cli create-ca -out /tmp/certs/ca &&
- es-gencert-cli create-node -ca-certificate /tmp/certs/ca/ca.crt -ca-key /tmp/certs/ca/ca.key -out \
- /tmp/certs/node -ip-addresses 127.0.0.1 -dns-names localhost,eventstoredb"
- user: "1000:1000"
- volumes:
- - "./certs:/tmp/certs"
diff --git a/samples/secure-with-tls/docker-compose.yml b/samples/secure-with-tls/docker-compose.yml
index 53ad888e6..f1078440f 100644
--- a/samples/secure-with-tls/docker-compose.yml
+++ b/samples/secure-with-tls/docker-compose.yml
@@ -1,43 +1,38 @@
version: "3.5"
-services:
- grpc.client:
- build: ./
- environment:
- # URL should match the DNS name in certificate and container name
- - ESDB_CONNECTION_STRING=esdb://eventstoredb:2113?Tls=true
- networks:
- - esdb_network
- depends_on:
- eventstoredb:
- condition: service_healthy
+networks:
+ default:
+ name: eventstore-network
- eventstoredb:
- image: eventstore/eventstore:20.10.0-buster-slim
- # container_name should match the DNS name in certificate
- container_name: eventstoredb
- environment:
- - EVENTSTORE_CLUSTER_SIZE=1
- - EVENTSTORE_RUN_PROJECTIONS=All
- - EVENTSTORE_ENABLE_EXTERNAL_TCP=true
- - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
- - EVENTSTORE_EXT_TCP_PORT=1113
- - EVENTSTORE_EXT_HTTP_PORT=2113
- # set certificates location
- - EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node/node.crt
- - EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node/node.key
- - EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
- ports:
- - 1113:1113
- - 2113:2113
- networks:
- - esdb_network
- volumes:
- # define volume that will copy pregenerated certificates
- - ./certs:/etc/eventstore/certs
- restart: unless-stopped
+services:
+
+ eventstore:
+ image: eventstore/eventstore:latest
+ container_name: eventstore
+ environment:
+ - EVENTSTORE_MEM_DB=true
+ - EVENTSTORE_HTTP_PORT=2113
+ - EVENTSTORE_LOG_LEVEL=Information
+ - EVENTSTORE_RUN_PROJECTIONS=None
+ - EVENTSTORE_START_STANDARD_PROJECTIONS=true
+ - EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP=true
+
+ # set certificates location
+ - EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node/node.crt
+ - EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node/node.key
+ - EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
+ ports:
+ - "2113:2113"
+ volumes:
+ - ./certs:/etc/eventstore/certs
+ - type: volume
+ source: eventstore-volume-data1
+ target: /var/lib/eventstore
+ - type: volume
+ source: eventstore-volume-logs1
+ target: /var/log/eventstore
+ restart: unless-stopped
-networks:
- esdb_network:
- name: eventstoredb.local
- driver: bridge
+volumes:
+ eventstore-volume-data1:
+ eventstore-volume-logs1:
diff --git a/samples/secure-with-tls/run-app.sh b/samples/secure-with-tls/run-app.sh
new file mode 100755
index 000000000..4bf5f1e27
--- /dev/null
+++ b/samples/secure-with-tls/run-app.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+echo "Going down..."
+docker-compose -f docker-compose.yml -f docker-compose.app.yml down
+
+echo "Going up..."
+docker-compose -f docker-compose.yml -f docker-compose.app.yml up --remove-orphans
diff --git a/samples/secure-with-tls/secure-with-tls.csproj b/samples/secure-with-tls/secure-with-tls.csproj
index 149de2f9b..7dd4b7c03 100644
--- a/samples/secure-with-tls/secure-with-tls.csproj
+++ b/samples/secure-with-tls/secure-with-tls.csproj
@@ -1,11 +1,21 @@
+ Exe
+ net8.0
secure_with_tls
+ enable
+ enable
+ Linux
+
+
+
+
+
-
+
-
\ No newline at end of file
+
diff --git a/samples/server-side-filtering/Program.cs b/samples/server-side-filtering/Program.cs
index e2e2c814e..243e40b60 100644
--- a/samples/server-side-filtering/Program.cs
+++ b/samples/server-side-filtering/Program.cs
@@ -1,174 +1,176 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using EventStore.Client;
+#pragma warning disable CS8321 // Local function is declared but never used
+
using EventTypeFilter = EventStore.Client.EventTypeFilter;
-namespace server_side_filtering {
- class Program {
- static async Task Main() {
- const int eventCount = 100;
- var semaphore = new SemaphoreSlim(eventCount);
-
- await using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://localhost:2113?tls=false")
- );
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- semaphore.Release();
- return Task.CompletedTask;
- },
- filterOptions: new SubscriptionFilterOptions(
- EventTypeFilter.Prefix("some-"),
- 1,
- (s, p, c) => {
- Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
- return Task.CompletedTask;
- })
- );
-
- await Task.Delay(2000);
-
- for (var i = 0; i < eventCount; i++) {
- var eventData = new EventData(
- Uuid.NewUuid(),
- i % 2 == 0 ? "some-event" : "other-event",
- Encoding.UTF8.GetBytes("{\"id\": \"1\" \"value\": \"some value\"}")
- );
-
- await client.AppendToStreamAsync(
- Guid.NewGuid().ToString("N"),
- StreamRevision.None,
- new List {eventData}
- );
- }
-
- await semaphore.WaitAsync();
+const int eventCount = 100;
+
+var semaphore = new SemaphoreSlim(eventCount);
+
+await using var client = new EventStoreClient(EventStoreClientSettings.Create("esdb://localhost:2113?tls=false"));
+
+await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ semaphore.Release();
+ return Task.CompletedTask;
+ },
+ filterOptions: new SubscriptionFilterOptions(
+ EventTypeFilter.Prefix("some-"),
+ 1,
+ (s, p, c) => {
+ Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
+ return Task.CompletedTask;
}
+ )
+);
+
+await Task.Delay(2000);
+
+for (var i = 0; i < eventCount; i++) {
+ var eventData = new EventData(
+ Uuid.NewUuid(),
+ i % 2 == 0 ? "some-event" : "other-event",
+ "{\"id\": \"1\" \"value\": \"some value\"}"u8.ToArray()
+ );
+
+ await client.AppendToStreamAsync(
+ Guid.NewGuid().ToString("N"),
+ StreamRevision.None,
+ new List { eventData }
+ );
+}
- private static async Task ExcludeSystemEvents(EventStoreClient client) {
- #region exclude-system
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: new SubscriptionFilterOptions(
- EventTypeFilter.ExcludeSystemEvents())
- );
- #endregion exclude-system
- }
+await semaphore.WaitAsync();
- private static async Task EventTypePrefix(EventStoreClient client) {
- #region event-type-prefix
- var filter = new SubscriptionFilterOptions(
- EventTypeFilter.Prefix("customer-"));
- #endregion event-type-prefix
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
- }
+return;
- private static async Task EventTypeRegex(EventStoreClient client) {
- #region event-type-regex
- var filter = new SubscriptionFilterOptions(
- EventTypeFilter.RegularExpression("^user|^company"));
- #endregion event-type-regex
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
- }
+static async Task ExcludeSystemEvents(EventStoreClient client) {
+ #region exclude-system
- private static async Task StreamPrefix(EventStoreClient client) {
- #region stream-prefix
- var filter = new SubscriptionFilterOptions(
- StreamFilter.Prefix("user-"));
- #endregion stream-prefix
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
- }
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: new SubscriptionFilterOptions(EventTypeFilter.ExcludeSystemEvents())
+ );
- private static async Task StreamRegex(EventStoreClient client) {
- #region stream-regex
- var filter = new SubscriptionFilterOptions(
- StreamFilter.RegularExpression("^account|^savings"));
- #endregion stream-regex
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
- }
+ #endregion exclude-system
+}
- private static async Task CheckpointCallback(EventStoreClient client) {
- #region checkpoint
- var filter = new SubscriptionFilterOptions(
- EventTypeFilter.ExcludeSystemEvents(),
- checkpointReached: (s, p, c) =>
- {
- Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
- return Task.CompletedTask;
- });
- #endregion checkpoint
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
- }
+static async Task EventTypePrefix(EventStoreClient client) {
+ #region event-type-prefix
+
+ var filter = new SubscriptionFilterOptions(EventTypeFilter.Prefix("customer-"));
+
+ #endregion event-type-prefix
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
+}
+
+static async Task EventTypeRegex(EventStoreClient client) {
+ #region event-type-regex
+
+ var filter = new SubscriptionFilterOptions(EventTypeFilter.RegularExpression("^user|^company"));
+
+ #endregion event-type-regex
- private static async Task CheckpointCallbackWithInterval(EventStoreClient client) {
- #region checkpoint-with-interval
- var filter = new SubscriptionFilterOptions(
- EventTypeFilter.ExcludeSystemEvents(),
- checkpointInterval: 1000,
- checkpointReached: (s, p, c) =>
- {
- Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
- return Task.CompletedTask;
- });
- #endregion checkpoint-with-interval
-
- await client.SubscribeToAllAsync(FromAll.Start,
- (s, e, c) => {
- Console.WriteLine(
- $"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
- return Task.CompletedTask;
- },
- filterOptions: filter
- );
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
+}
+
+static async Task StreamPrefix(EventStoreClient client) {
+ #region stream-prefix
+
+ var filter = new SubscriptionFilterOptions(StreamFilter.Prefix("user-"));
+
+ #endregion stream-prefix
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
+}
+
+static async Task StreamRegex(EventStoreClient client) {
+ #region stream-regex
+
+ var filter = new SubscriptionFilterOptions(StreamFilter.RegularExpression("^account|^savings"));
+
+ #endregion stream-regex
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
+}
+
+static async Task CheckpointCallback(EventStoreClient client) {
+ #region checkpoint
+
+ var filter = new SubscriptionFilterOptions(
+ EventTypeFilter.ExcludeSystemEvents(),
+ checkpointReached: (s, p, c) => {
+ Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
+ return Task.CompletedTask;
}
- }
+ );
+
+ #endregion checkpoint
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
}
+
+static async Task CheckpointCallbackWithInterval(EventStoreClient client) {
+ #region checkpoint-with-interval
+
+ var filter = new SubscriptionFilterOptions(
+ EventTypeFilter.ExcludeSystemEvents(),
+ 1000,
+ (s, p, c) => {
+ Console.WriteLine($"checkpoint taken at {p.PreparePosition}");
+ return Task.CompletedTask;
+ }
+ );
+
+ #endregion checkpoint-with-interval
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ (s, e, c) => {
+ Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.PreparePosition}");
+ return Task.CompletedTask;
+ },
+ filterOptions: filter
+ );
+}
\ No newline at end of file
diff --git a/samples/server-side-filtering/server-side-filtering.csproj b/samples/server-side-filtering/server-side-filtering.csproj
index 34b2d4c39..b69b90670 100644
--- a/samples/server-side-filtering/server-side-filtering.csproj
+++ b/samples/server-side-filtering/server-side-filtering.csproj
@@ -1,14 +1,12 @@
-
server_side_filtering
-
+
-
\ No newline at end of file
diff --git a/samples/setting-up-dependency-injection/Controllers/EventStoreController.cs b/samples/setting-up-dependency-injection/Controllers/EventStoreController.cs
index d1ad74a8c..d4c3f4d59 100644
--- a/samples/setting-up-dependency-injection/Controllers/EventStoreController.cs
+++ b/samples/setting-up-dependency-injection/Controllers/EventStoreController.cs
@@ -1,12 +1,9 @@
-using System.Collections.Generic;
-using EventStore.Client;
-using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc;
namespace setting_up_dependency_injection.Controllers {
[ApiController]
[Route("[controller]")]
public class EventStoreController : ControllerBase {
-
#region using-dependency
private readonly EventStoreClient _eventStoreClient;
diff --git a/samples/setting-up-dependency-injection/Program.cs b/samples/setting-up-dependency-injection/Program.cs
index f1d6624d7..49b316496 100644
--- a/samples/setting-up-dependency-injection/Program.cs
+++ b/samples/setting-up-dependency-injection/Program.cs
@@ -1,20 +1,12 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Hosting;
+namespace setting_up_dependency_injection;
-namespace setting_up_dependency_injection {
- public class Program {
- public static async Task Main(string[] args) {
- using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
- await CreateHostBuilder(args).Build().WaitForShutdownAsync(cts.Token);
- }
-
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder => {
- webBuilder.UseStartup();
- });
+public class Program {
+ public static async Task Main(string[] args) {
+ using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
+ await CreateHostBuilder(args).Build().WaitForShutdownAsync(cts.Token);
}
-}
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); });
+}
\ No newline at end of file
diff --git a/samples/setting-up-dependency-injection/Startup.cs b/samples/setting-up-dependency-injection/Startup.cs
index 7e28c1d53..a1d618aff 100644
--- a/samples/setting-up-dependency-injection/Startup.cs
+++ b/samples/setting-up-dependency-injection/Startup.cs
@@ -1,38 +1,25 @@
-using System;
-using System.Net.Http;
-using EventStore.Client;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-
-namespace setting_up_dependency_injection {
- public class Startup {
- public Startup(IConfiguration configuration) {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- public void ConfigureServices(IServiceCollection services) {
- services.AddControllers();
-
- #region setting-up-dependency
- services.AddEventStoreClient("esdb://admin:changeit@localhost:2113?tls=false");
- #endregion setting-up-dependency
- }
-
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
- if (env.IsDevelopment()) {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseHttpsRedirection();
- app.UseRouting();
- app.UseEndpoints(endpoints => {
- endpoints.MapControllers();
- });
- }
+namespace setting_up_dependency_injection;
+
+public class Startup {
+ public Startup(IConfiguration configuration) => Configuration = configuration;
+
+ public IConfiguration Configuration { get; }
+
+ public void ConfigureServices(IServiceCollection services) {
+ services.AddControllers();
+
+ #region setting-up-dependency
+
+ services.AddEventStoreClient("esdb://admin:changeit@localhost:2113?tls=false");
+
+ #endregion setting-up-dependency
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
+ if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
+
+ app.UseHttpsRedirection();
+ app.UseRouting();
+ app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
-}
+}
\ No newline at end of file
diff --git a/samples/setting-up-dependency-injection/setting-up-dependency-injection.csproj b/samples/setting-up-dependency-injection/setting-up-dependency-injection.csproj
index 7f3b511bd..0e2adfd05 100644
--- a/samples/setting-up-dependency-injection/setting-up-dependency-injection.csproj
+++ b/samples/setting-up-dependency-injection/setting-up-dependency-injection.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/samples/subscribing-to-streams/Program.cs b/samples/subscribing-to-streams/Program.cs
index 724b1b2e5..b0a59ea22 100644
--- a/samples/subscribing-to-streams/Program.cs
+++ b/samples/subscribing-to-streams/Program.cs
@@ -1,162 +1,185 @@
-using System;
-using System.Net.Http;
-using System.Reflection.Metadata;
-using System.Threading;
-using System.Threading.Tasks;
-using EventStore.Client;
-using EventStore.Client.Streams;
-
-namespace subscribing_to_streams {
- class Program {
- static async Task Main(string[] args) {
- using var client = new EventStoreClient(
- EventStoreClientSettings.Create("esdb://localhost:2113?tls=false")
- );
-
- await SubscribeToStream(client);
- await SubscribeToAll(client);
- await OverridingUserCredentials(client);
- }
+#pragma warning disable CS8321 // Local function is declared but never used
- private static async Task SubscribeToStream(EventStoreClient client) {
- #region subscribe-to-stream
- await client.SubscribeToStreamAsync("some-stream",
- FromStream.Start,
- async (subscription, evnt, cancellationToken) => {
- Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}");
- await HandleEvent(evnt);
- });
- #endregion subscribe-to-stream
-
- #region subscribe-to-stream-from-position
- await client.SubscribeToStreamAsync(
- "some-stream",
- FromStream.After(StreamPosition.FromInt64(20)),
- EventAppeared);
- #endregion subscribe-to-stream-from-position
-
- #region subscribe-to-stream-live
- await client.SubscribeToStreamAsync(
- "some-stream",
- FromStream.End,
- EventAppeared);
- #endregion subscribe-to-stream-live
-
- #region subscribe-to-stream-resolving-linktos
- await client.SubscribeToStreamAsync(
- "$et-myEventType",
- FromStream.Start,
- EventAppeared,
- resolveLinkTos: true);
- #endregion subscribe-to-stream-resolving-linktos
-
- #region subscribe-to-stream-subscription-dropped
-
- var checkpoint = await ReadStreamCheckpointAsync();
- await client.SubscribeToStreamAsync(
- "some-stream",
- checkpoint is null ? FromStream.Start : FromStream.After(checkpoint.Value),
- eventAppeared: async (subscription, evnt, cancellationToken) => {
- await HandleEvent(evnt);
- checkpoint = evnt.OriginalEventNumber;
- },
- subscriptionDropped: ((subscription, reason, exception) => {
- Console.WriteLine($"Subscription was dropped due to {reason}. {exception}");
- if (reason != SubscriptionDroppedReason.Disposed) {
- // Resubscribe if the client didn't stop the subscription
- Resubscribe(checkpoint);
- }
- }));
- #endregion subscribe-to-stream-subscription-dropped
- }
+// ReSharper disable UnusedParameter.Local
+// ReSharper disable UnusedVariable
- private static async Task SubscribeToAll(EventStoreClient client) {
- #region subscribe-to-all
- await client.SubscribeToAllAsync(
- FromAll.Start,
- async (subscription, evnt, cancellationToken) => {
- Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}");
- await HandleEvent(evnt);
- });
- #endregion subscribe-to-all
-
- #region subscribe-to-all-from-position
-
- var result = await client.AppendToStreamAsync("subscribe-to-all-from-position", StreamState.NoStream, new[] {
- new EventData(Uuid.NewUuid(), "-", ReadOnlyMemory.Empty)
- });
-
- await client.SubscribeToAllAsync(
- FromAll.After(result.LogPosition),
- EventAppeared);
- #endregion subscribe-to-all-from-position
-
- #region subscribe-to-all-live
- await client.SubscribeToAllAsync(
- FromAll.End,
- EventAppeared);
- #endregion subscribe-to-all-live
-
- #region subscribe-to-all-subscription-dropped
- var checkpoint = await ReadCheckpointAsync();
- await client.SubscribeToAllAsync(
- checkpoint is null ? FromAll.Start : FromAll.After(checkpoint.Value),
- eventAppeared: async (subscription, evnt, cancellationToken) => {
- await HandleEvent(evnt);
- checkpoint = evnt.OriginalPosition!.Value;
- },
- subscriptionDropped: ((subscription, reason, exception) => {
- Console.WriteLine($"Subscription was dropped due to {reason}. {exception}");
- if (reason != SubscriptionDroppedReason.Disposed) {
- // Resubscribe if the client didn't stop the subscription
- Resubscribe(checkpoint);
- }
- }));
- #endregion subscribe-to-all-subscription-dropped
- }
+await using var client = new EventStoreClient(EventStoreClientSettings.Create("esdb://localhost:2113?tls=false"));
+
+await SubscribeToStream(client);
+await SubscribeToAll(client);
+await OverridingUserCredentials(client);
+
+return;
- private static async Task SubscribeToFiltered(EventStoreClient client) {
- #region stream-prefix-filtered-subscription
- var prefixStreamFilter = new SubscriptionFilterOptions(StreamFilter.Prefix("test-", "other-"));
- await client.SubscribeToAllAsync(
- FromAll.Start,
- EventAppeared,
- filterOptions: prefixStreamFilter);
- #endregion stream-prefix-filtered-subscription
-
- #region stream-regex-filtered-subscription
- var regexStreamFilter = StreamFilter.RegularExpression(@"/invoice-\d\d\d/g");
- #endregion stream-regex-filtered-subscription
+static async Task SubscribeToStream(EventStoreClient client) {
+ #region subscribe-to-stream
+
+ await client.SubscribeToStreamAsync(
+ "some-stream",
+ FromStream.Start,
+ async (subscription, evnt, cancellationToken) => {
+ Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}");
+ await HandleEvent(evnt);
}
+ );
+
+ #endregion subscribe-to-stream
+
+ #region subscribe-to-stream-from-position
+
+ await client.SubscribeToStreamAsync(
+ "some-stream",
+ FromStream.After(StreamPosition.FromInt64(20)),
+ EventAppeared
+ );
+
+ #endregion subscribe-to-stream-from-position
- private static async Task OverridingUserCredentials(EventStoreClient client) {
- #region overriding-user-credentials
- await client.SubscribeToAllAsync(
- FromAll.Start,
- EventAppeared,
- userCredentials: new UserCredentials("admin", "changeit"));
- #endregion overriding-user-credentials
+ #region subscribe-to-stream-live
+
+ await client.SubscribeToStreamAsync(
+ "some-stream",
+ FromStream.End,
+ EventAppeared
+ );
+
+ #endregion subscribe-to-stream-live
+
+ #region subscribe-to-stream-resolving-linktos
+
+ await client.SubscribeToStreamAsync(
+ "$et-myEventType",
+ FromStream.Start,
+ EventAppeared,
+ true
+ );
+
+ #endregion subscribe-to-stream-resolving-linktos
+
+ #region subscribe-to-stream-subscription-dropped
+
+ var checkpoint = await ReadStreamCheckpointAsync();
+ await client.SubscribeToStreamAsync(
+ "some-stream",
+ checkpoint is null ? FromStream.Start : FromStream.After(checkpoint.Value),
+ async (subscription, evnt, cancellationToken) => {
+ await HandleEvent(evnt);
+ checkpoint = evnt.OriginalEventNumber;
+ },
+ subscriptionDropped: (subscription, reason, exception) => {
+ Console.WriteLine($"Subscription was dropped due to {reason}. {exception}");
+ if (reason != SubscriptionDroppedReason.Disposed)
+ // Resubscribe if the client didn't stop the subscription
+ ResubscribeToStream(checkpoint);
}
+ );
+
+ #endregion subscribe-to-stream-subscription-dropped
+}
- private static Task EventAppeared(StreamSubscription subscription, ResolvedEvent evnt,
- CancellationToken cancellationToken) {
- return Task.CompletedTask;
+static async Task SubscribeToAll(EventStoreClient client) {
+ #region subscribe-to-all
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ async (subscription, evnt, cancellationToken) => {
+ Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}");
+ await HandleEvent(evnt);
}
+ );
+
+ #endregion subscribe-to-all
+
+ #region subscribe-to-all-from-position
- private static void SubscriptionDropped(StreamSubscription subscription, SubscriptionDroppedReason reason,
- Exception ex) {
+ var result = await client.AppendToStreamAsync(
+ "subscribe-to-all-from-position",
+ StreamState.NoStream,
+ new[] {
+ new EventData(Uuid.NewUuid(), "-", ReadOnlyMemory.Empty)
}
- private static Task HandleEvent(ResolvedEvent evnt) {
- return Task.CompletedTask;
+ );
+
+ await client.SubscribeToAllAsync(
+ FromAll.After(result.LogPosition),
+ EventAppeared
+ );
+
+ #endregion subscribe-to-all-from-position
+
+ #region subscribe-to-all-live
+
+ await client.SubscribeToAllAsync(
+ FromAll.End,
+ EventAppeared
+ );
+
+ #endregion subscribe-to-all-live
+
+ #region subscribe-to-all-subscription-dropped
+
+ var checkpoint = await ReadCheckpointAsync();
+ await client.SubscribeToAllAsync(
+ checkpoint is null ? FromAll.Start : FromAll.After(checkpoint.Value),
+ async (subscription, evnt, cancellationToken) => {
+ await HandleEvent(evnt);
+ checkpoint = evnt.OriginalPosition!.Value;
+ },
+ subscriptionDropped: (subscription, reason, exception) => {
+ Console.WriteLine($"Subscription was dropped due to {reason}. {exception}");
+ if (reason != SubscriptionDroppedReason.Disposed)
+ // Resubscribe if the client didn't stop the subscription
+ Resubscribe(checkpoint);
}
+ );
+
+ #endregion subscribe-to-all-subscription-dropped
+}
- private static void Resubscribe(StreamPosition? checkpoint) { }
- private static void Resubscribe(Position? checkpoint) { }
+static async Task SubscribeToFiltered(EventStoreClient client) {
+ #region stream-prefix-filtered-subscription
- private static Task ReadStreamCheckpointAsync() =>
- Task.FromResult(new StreamPosition?());
+ var prefixStreamFilter = new SubscriptionFilterOptions(StreamFilter.Prefix("test-", "other-"));
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ EventAppeared,
+ filterOptions: prefixStreamFilter
+ );
- private static Task ReadCheckpointAsync() =>
- Task.FromResult(new Position?());
- }
+ #endregion stream-prefix-filtered-subscription
+
+ #region stream-regex-filtered-subscription
+
+ var regexStreamFilter = StreamFilter.RegularExpression(@"/invoice-\d\d\d/g");
+
+ #endregion stream-regex-filtered-subscription
}
+
+static async Task OverridingUserCredentials(EventStoreClient client) {
+ #region overriding-user-credentials
+
+ await client.SubscribeToAllAsync(
+ FromAll.Start,
+ EventAppeared,
+ userCredentials: new UserCredentials("admin", "changeit")
+ );
+
+ #endregion overriding-user-credentials
+}
+
+static Task EventAppeared(StreamSubscription subscription, ResolvedEvent evnt, CancellationToken cancellationToken) =>
+ Task.CompletedTask;
+
+static void SubscriptionDropped(StreamSubscription subscription, SubscriptionDroppedReason reason, Exception ex) { }
+
+static Task HandleEvent(ResolvedEvent evnt) => Task.CompletedTask;
+
+static void ResubscribeToStream(StreamPosition? checkpoint) { }
+
+static void Resubscribe(Position? checkpoint) { }
+
+static Task ReadStreamCheckpointAsync() =>
+ Task.FromResult(new StreamPosition?());
+
+static Task ReadCheckpointAsync() =>
+ Task.FromResult(new Position?());
\ No newline at end of file
diff --git a/samples/subscribing-to-streams/subscribing-to-streams.csproj b/samples/subscribing-to-streams/subscribing-to-streams.csproj
index d67c0a569..397f07197 100644
--- a/samples/subscribing-to-streams/subscribing-to-streams.csproj
+++ b/samples/subscribing-to-streams/subscribing-to-streams.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/test/EventStore.Client.Tests.Common/Extensions/EnumerableTaskExtensions.cs b/src/EventStore.Client.Common/EnumerableTaskExtensions.cs
similarity index 75%
rename from test/EventStore.Client.Tests.Common/Extensions/EnumerableTaskExtensions.cs
rename to src/EventStore.Client.Common/EnumerableTaskExtensions.cs
index fd62d7b4c..eb4517006 100644
--- a/test/EventStore.Client.Tests.Common/Extensions/EnumerableTaskExtensions.cs
+++ b/src/EventStore.Client.Common/EnumerableTaskExtensions.cs
@@ -1,8 +1,8 @@
using System.Diagnostics;
-namespace EventStore.Client.Tests;
+namespace EventStore.Client;
-public static class EnumerableTaskExtensions {
+static class EnumerableTaskExtensions {
[DebuggerStepThrough]
public static Task WhenAll(this IEnumerable source) => Task.WhenAll(source);
diff --git a/src/EventStore.Client.Operations/EventStoreOperationsClient.cs b/src/EventStore.Client.Operations/EventStoreOperationsClient.cs
index 156d0eda0..672383348 100644
--- a/src/EventStore.Client.Operations/EventStoreOperationsClient.cs
+++ b/src/EventStore.Client.Operations/EventStoreOperationsClient.cs
@@ -1,38 +1,33 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Grpc.Core;
+using Grpc.Core;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
-namespace EventStore.Client {
- ///
- /// The client used to perform maintenance and other administrative tasks on the EventStoreDB.
- ///
- public sealed partial class EventStoreOperationsClient : EventStoreClientBase {
- private static readonly IDictionary> ExceptionMap =
- new Dictionary> {
- [Constants.Exceptions.ScavengeNotFound] = ex => new ScavengeNotFoundException(ex.Trailers
- .FirstOrDefault(x => x.Key == Constants.Exceptions.ScavengeId)?.Value)
- };
+namespace EventStore.Client;
- private readonly ILogger _log;
+///
+/// The client used to perform maintenance and other administrative tasks on the EventStoreDB.
+///
+public sealed partial class EventStoreOperationsClient : EventStoreClientBase {
+ static readonly Dictionary> ExceptionMap =
+ new() {
+ [Constants.Exceptions.ScavengeNotFound] = ex => new ScavengeNotFoundException(
+ ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.ScavengeId)?.Value
+ )
+ };
- ///
- /// Constructs a new . This method is not intended to be called directly in your code.
- ///
- ///
- public EventStoreOperationsClient(IOptions options) : this(options.Value) {
- }
+ readonly ILogger _log;
- ///
- /// Constructs a new .
- ///
- ///
- public EventStoreOperationsClient(EventStoreClientSettings? settings = null) : base(settings, ExceptionMap) {
- _log = Settings.LoggerFactory?.CreateLogger() ??
- new NullLogger();
- }
- }
-}
+ ///
+ /// Constructs a new . This method is not intended to be called directly in your code.
+ ///
+ ///
+ public EventStoreOperationsClient(IOptions options) : this(options.Value) { }
+
+ ///
+ /// Constructs a new .
+ ///
+ ///
+ public EventStoreOperationsClient(EventStoreClientSettings? settings = null) : base(settings, ExceptionMap) =>
+ _log = Settings.LoggerFactory?.CreateLogger() ?? new NullLogger();
+}
\ No newline at end of file
diff --git a/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs b/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs
index 87969c677..0047e1c73 100644
--- a/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs
+++ b/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs
@@ -141,8 +141,7 @@ private async Task Subscribe() {
_log.LogDebug("Persistent Subscription {subscriptionId} confirmed.", SubscriptionId);
try {
- await foreach (var response in
- _call.ResponseStream.ReadAllAsync(_cancellationToken).ConfigureAwait(false)) {
+ await foreach (var response in _call.ResponseStream.ReadAllAsync(_cancellationToken).ConfigureAwait(false)) {
if (response.ContentCase != ReadResp.ContentOneofCase.Event) {
continue;
}
diff --git a/src/EventStore.Client.Streams/EventStoreClient.cs b/src/EventStore.Client.Streams/EventStoreClient.cs
index cace19051..33041d303 100644
--- a/src/EventStore.Client.Streams/EventStoreClient.cs
+++ b/src/EventStore.Client.Streams/EventStoreClient.cs
@@ -30,35 +30,19 @@ public sealed partial class EventStoreClient : EventStoreClientBase {
private static readonly Dictionary> ExceptionMap = new() {
- [Constants.Exceptions.InvalidTransaction] =
- ex => new InvalidTransactionException(ex.Message, ex),
- [Constants.Exceptions.StreamDeleted] = ex => new StreamDeletedException(
- ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value ??
- "",
- ex),
- [Constants.Exceptions.WrongExpectedVersion] = ex => new WrongExpectedVersionException(
- ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value!,
- ex.Trailers.GetStreamRevision(Constants.Exceptions.ExpectedVersion),
- ex.Trailers.GetStreamRevision(Constants.Exceptions.ActualVersion),
- ex, ex.Message),
- [Constants.Exceptions.MaximumAppendSizeExceeded] = ex =>
- new MaximumAppendSizeExceededException(
- ex.Trailers.GetIntValueOrDefault(Constants.Exceptions.MaximumAppendSize), ex),
- [Constants.Exceptions.StreamNotFound] = ex => new StreamNotFoundException(
- ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value!, ex),
- [Constants.Exceptions.MissingRequiredMetadataProperty] = ex => new
- RequiredMetadataPropertyMissingException(
- ex.Trailers.FirstOrDefault(x =>
- x.Key == Constants.Exceptions.MissingRequiredMetadataProperty)
- ?.Value!, ex),
+ [Constants.Exceptions.InvalidTransaction] = ex => new InvalidTransactionException(ex.Message, ex),
+ [Constants.Exceptions.StreamDeleted] = ex => new StreamDeletedException(ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value ?? "", ex),
+ [Constants.Exceptions.WrongExpectedVersion] = ex => new WrongExpectedVersionException(ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value!, ex.Trailers.GetStreamRevision(Constants.Exceptions.ExpectedVersion), ex.Trailers.GetStreamRevision(Constants.Exceptions.ActualVersion), ex, ex.Message),
+ [Constants.Exceptions.MaximumAppendSizeExceeded] = ex => new MaximumAppendSizeExceededException(ex.Trailers.GetIntValueOrDefault(Constants.Exceptions.MaximumAppendSize), ex),
+ [Constants.Exceptions.StreamNotFound] = ex => new StreamNotFoundException(ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.StreamName)?.Value!, ex),
+ [Constants.Exceptions.MissingRequiredMetadataProperty] = ex => new RequiredMetadataPropertyMissingException(ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.MissingRequiredMetadataProperty)?.Value!, ex),
};
///
/// Constructs a new . This is not intended to be called directly from your code.
///
///
- public EventStoreClient(IOptions options) : this(options.Value) {
- }
+ public EventStoreClient(IOptions options) : this(options.Value) { }
///
/// Constructs a new .
@@ -71,9 +55,7 @@ public EventStoreClient(EventStoreClientSettings? settings = null) : base(settin
}
private void SwapStreamAppender(Exception ex) =>
- Interlocked.Exchange(ref _streamAppenderLazy,
- new Lazy(CreateStreamAppender))
- .Value.Dispose();
+ Interlocked.Exchange(ref _streamAppenderLazy, new Lazy(CreateStreamAppender)).Value.Dispose();
// todo: might be nice to have two different kinds of appenders and we decide which to instantiate according to the server caps.
private StreamAppender CreateStreamAppender() {
diff --git a/src/EventStore.Client.UserManagement/EventStoreUserManagementClient.cs b/src/EventStore.Client.UserManagement/EventStoreUserManagementClient.cs
index a0680cbf6..6b86e81b4 100644
--- a/src/EventStore.Client.UserManagement/EventStoreUserManagementClient.cs
+++ b/src/EventStore.Client.UserManagement/EventStoreUserManagementClient.cs
@@ -270,7 +270,7 @@ public async Task ResetPasswordAsync(string loginName, string newPassword,
await call.ResponseAsync.ConfigureAwait(false);
}
- private static readonly IDictionary> ExceptionMap =
+ private static readonly Dictionary> ExceptionMap =
new Dictionary> {
[Constants.Exceptions.UserNotFound] = ex => new UserNotFoundException(
ex.Trailers.First(x => x.Key == Constants.Exceptions.LoginName).Value),
diff --git a/src/EventStore.Client/ChannelBaseExtensions.cs b/src/EventStore.Client/ChannelBaseExtensions.cs
index eb078ae2e..3edbf59fd 100644
--- a/src/EventStore.Client/ChannelBaseExtensions.cs
+++ b/src/EventStore.Client/ChannelBaseExtensions.cs
@@ -1,15 +1,10 @@
-using System;
-using System.Threading.Tasks;
using Grpc.Core;
-namespace EventStore.Client {
- internal static class ChannelBaseExtensions {
- public static async ValueTask DisposeAsync(this ChannelBase channel) {
- // for grpc.core, shutdown does the cleanup and the cast returns null
- // for grpc.net shutdown does nothing and dispose does the cleanup
- await channel.ShutdownAsync().ConfigureAwait(false);
+namespace EventStore.Client;
- (channel as IDisposable)?.Dispose();
- }
+static class ChannelBaseExtensions {
+ public static async ValueTask DisposeAsync(this ChannelBase channel) {
+ await channel.ShutdownAsync().ConfigureAwait(false);
+ (channel as IDisposable)?.Dispose();
}
-}
+}
\ No newline at end of file
diff --git a/src/EventStore.Client/ChannelCache.cs b/src/EventStore.Client/ChannelCache.cs
index 1ed172bc6..a3369e25f 100644
--- a/src/EventStore.Client/ChannelCache.cs
+++ b/src/EventStore.Client/ChannelCache.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Threading.Tasks;
-
+using System.Net;
using TChannel = Grpc.Net.Client.GrpcChannel;
namespace EventStore.Client {
@@ -11,7 +6,6 @@ namespace EventStore.Client {
// Deals with the disposal difference between grpc.net and grpc.core
// Thread safe.
internal class ChannelCache :
- IDisposable, // for grpc.net we can dispose synchronously, but not for grpc.core
IAsyncDisposable {
private readonly EventStoreClientSettings _settings;
diff --git a/src/EventStore.Client/EventStore.Client.csproj b/src/EventStore.Client/EventStore.Client.csproj
index ca10005c9..92a14142f 100644
--- a/src/EventStore.Client/EventStore.Client.csproj
+++ b/src/EventStore.Client/EventStore.Client.csproj
@@ -6,10 +6,10 @@
EventStore.Client.Grpc
-
-
-
-
+
+
+
+
diff --git a/src/EventStore.Client/EventStoreClientBase.cs b/src/EventStore.Client/EventStoreClientBase.cs
index d3252a330..39f579fcc 100644
--- a/src/EventStore.Client/EventStoreClientBase.cs
+++ b/src/EventStore.Client/EventStoreClientBase.cs
@@ -14,7 +14,7 @@ public abstract class EventStoreClientBase :
IDisposable, // for grpc.net we can dispose synchronously, but not for grpc.core
IAsyncDisposable {
- private readonly IDictionary> _exceptionMap;
+ private readonly Dictionary> _exceptionMap;
private readonly CancellationTokenSource _cts;
private readonly ChannelCache _channelCache;
private readonly SharingProvider _channelInfoProvider;
@@ -28,7 +28,7 @@ public abstract class EventStoreClientBase :
/// Constructs a new .
protected EventStoreClientBase(EventStoreClientSettings? settings,
- IDictionary> exceptionMap) {
+ Dictionary> exceptionMap) {
Settings = settings ?? new EventStoreClientSettings();
_exceptionMap = exceptionMap;
_cts = new CancellationTokenSource();
diff --git a/src/EventStore.Client/Interceptors/TypedExceptionInterceptor.cs b/src/EventStore.Client/Interceptors/TypedExceptionInterceptor.cs
index f49307287..75754f95f 100644
--- a/src/EventStore.Client/Interceptors/TypedExceptionInterceptor.cs
+++ b/src/EventStore.Client/Interceptors/TypedExceptionInterceptor.cs
@@ -1,119 +1,142 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
+
+using System.Diagnostics.CodeAnalysis;
using Grpc.Core;
using Grpc.Core.Interceptors;
+using static EventStore.Client.Constants;
+using static Grpc.Core.StatusCode;
+
+namespace EventStore.Client.Interceptors;
+
+class TypedExceptionInterceptor : Interceptor {
+ static readonly Dictionary> DefaultExceptionMap = new() {
+ [Exceptions.AccessDenied] = ex => ex.ToAccessDeniedException(),
+ [Exceptions.NotLeader] = ex => ex.ToNotLeaderException(),
+ };
-namespace EventStore.Client.Interceptors {
- internal class TypedExceptionInterceptor : Interceptor {
- private static readonly IDictionary> DefaultExceptionMap =
- new Dictionary> {
- [Constants.Exceptions.AccessDenied] = ex => new AccessDeniedException(ex.Message, ex),
- [Constants.Exceptions.NotLeader] = ex => new NotLeaderException(
- ex.Trailers.FirstOrDefault(x => x.Key == Constants.Exceptions.LeaderEndpointHost)?.Value!,
- ex.Trailers.GetIntValueOrDefault(Constants.Exceptions.LeaderEndpointPort), ex)
+ public TypedExceptionInterceptor(Dictionary> customExceptionMap) {
+ var map = new Dictionary>(DefaultExceptionMap.Concat(customExceptionMap));
+
+ ConvertRpcException = rpcEx => {
+ if (rpcEx.TryMapException(map, out var ex))
+ throw ex;
+
+ throw rpcEx.StatusCode switch {
+ Unavailable when rpcEx.Status.Detail == "Deadline Exceeded" => rpcEx.ToDeadlineExceededRpcException(),
+ Unauthenticated => rpcEx.ToNotAuthenticatedException(),
+ _ => rpcEx
};
+ };
+ }
- private readonly IDictionary> _exceptionMap;
+ Func ConvertRpcException { get; }
+
+ public override AsyncServerStreamingCall AsyncServerStreamingCall(
+ TRequest request,
+ ClientInterceptorContext context,
+ AsyncServerStreamingCallContinuation continuation
+ ) {
+ var response = continuation(request, context);
+
+ return new AsyncServerStreamingCall(
+ response.ResponseStream.Apply(ConvertRpcException),
+ response.ResponseHeadersAsync,
+ response.GetStatus,
+ response.GetTrailers,
+ response.Dispose
+ );
+ }
- public TypedExceptionInterceptor(IDictionary> exceptionMap) {
- _exceptionMap = new Dictionary>(DefaultExceptionMap);
- foreach (var pair in exceptionMap) {
- _exceptionMap.Add(pair);
- }
- }
+ public override AsyncClientStreamingCall AsyncClientStreamingCall(
+ ClientInterceptorContext context,
+ AsyncClientStreamingCallContinuation continuation
+ ) {
+ var response = continuation(context);
+
+ return new AsyncClientStreamingCall(
+ response.RequestStream,
+ response.ResponseAsync.Apply(ConvertRpcException),
+ response.ResponseHeadersAsync,
+ response.GetStatus,
+ response.GetTrailers,
+ response.Dispose
+ );
+ }
- public override AsyncServerStreamingCall AsyncServerStreamingCall(
- TRequest request,
- ClientInterceptorContext context,
- AsyncServerStreamingCallContinuation continuation) {
- var response = continuation(request, context);
+ public override AsyncUnaryCall AsyncUnaryCall(
+ TRequest request,
+ ClientInterceptorContext context,
+ AsyncUnaryCallContinuation continuation
+ ) {
+ var response = continuation(request, context);
+
+ return new AsyncUnaryCall(
+ response.ResponseAsync.Apply(ConvertRpcException),
+ response.ResponseHeadersAsync,
+ response.GetStatus,
+ response.GetTrailers,
+ response.Dispose
+ );
+ }
- return new AsyncServerStreamingCall(
- new AsyncStreamReader(_exceptionMap, response.ResponseStream),
- response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose);
- }
+ public override AsyncDuplexStreamingCall AsyncDuplexStreamingCall(
+ ClientInterceptorContext context,
+ AsyncDuplexStreamingCallContinuation continuation
+ ) {
+ var response = continuation(context);
+
+ return new AsyncDuplexStreamingCall(
+ response.RequestStream,
+ response.ResponseStream.Apply(ConvertRpcException),
+ response.ResponseHeadersAsync,
+ response.GetStatus,
+ response.GetTrailers,
+ response.Dispose
+ );
+ }
+}
- public override AsyncClientStreamingCall AsyncClientStreamingCall(
- ClientInterceptorContext context,
- AsyncClientStreamingCallContinuation continuation) {
- var response = continuation(context);
-
- return new AsyncClientStreamingCall(
- response.RequestStream,
- response.ResponseAsync.ContinueWith(t => t.Exception?.InnerException is RpcException ex
- ? throw ConvertRpcException(ex, _exceptionMap)
- : t.Result),
- response.ResponseHeadersAsync,
- response.GetStatus,
- response.GetTrailers,
- response.Dispose);
- }
+static class RpcExceptionConversionExtensions {
+ public static IAsyncStreamReader Apply(this IAsyncStreamReader reader, Func convertException) =>
+ new ExceptionConverterStreamReader(reader, convertException);
- public override AsyncUnaryCall AsyncUnaryCall(
- TRequest request,
- ClientInterceptorContext context,
- AsyncUnaryCallContinuation continuation) {
- var response = continuation(request, context);
-
- return new AsyncUnaryCall(response.ResponseAsync.ContinueWith(t =>
- t.Exception?.InnerException is RpcException ex
- ? throw ConvertRpcException(ex, _exceptionMap)
- : t.Result), response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers,
- response.Dispose);
- }
+ public static Task Apply(this Task task, Func convertException) =>
+ task.ContinueWith(t => t.Exception?.InnerException is RpcException ex ? throw convertException(ex) : t.Result);
+
+ public static AccessDeniedException ToAccessDeniedException(this RpcException exception) =>
+ new(exception.Message, exception);
- public override AsyncDuplexStreamingCall AsyncDuplexStreamingCall(
- ClientInterceptorContext context,
- AsyncDuplexStreamingCallContinuation continuation) {
- var response = continuation(context);
-
- return new AsyncDuplexStreamingCall(
- response.RequestStream,
- new AsyncStreamReader(_exceptionMap, response.ResponseStream),
- response.ResponseHeadersAsync,
- response.GetStatus,
- response.GetTrailers,
- response.Dispose);
- }
+ public static NotLeaderException ToNotLeaderException(this RpcException exception) {
+ var host = exception.Trailers.FirstOrDefault(x => x.Key == Exceptions.LeaderEndpointHost)?.Value!;
+ var port = exception.Trailers.GetIntValueOrDefault(Exceptions.LeaderEndpointPort);
+ return new NotLeaderException(host, port, exception);
+ }
+
+ public static NotAuthenticatedException ToNotAuthenticatedException(this RpcException exception) =>
+ new(exception.Message, exception);
- private static Exception ConvertRpcException(RpcException ex,
- IDictionary> exceptionMap) {
- Func? factory = null;
- return (ex.Trailers.TryGetValue(Constants.Exceptions.ExceptionKey, out var key) &&
- exceptionMap.TryGetValue(key!, out factory)) switch {
- true => factory!.Invoke(ex),
- false => (ex.StatusCode, ex.Status.Detail) switch {
- (StatusCode.Unavailable, "Deadline Exceeded") => new RpcException(new Status(
- StatusCode.DeadlineExceeded, ex.Status.Detail, ex.Status.DebugException)),
- (StatusCode.DeadlineExceeded, _) => ex,
- (StatusCode.Unauthenticated, _) => new NotAuthenticatedException(ex.Message, ex),
- _ => ex
- }
- };
+ public static RpcException ToDeadlineExceededRpcException(this RpcException exception) =>
+ new(new Status(DeadlineExceeded, exception.Status.Detail, exception.Status.DebugException));
+
+ public static bool TryMapException(this RpcException exception, Dictionary> map, [MaybeNullWhen(false)] out Exception createdException) {
+ if (exception.Trailers.TryGetValue(Exceptions.ExceptionKey, out var key) && map.TryGetValue(key!, out var factory)) {
+ createdException = factory.Invoke(exception);
+ return true;
}
- private class AsyncStreamReader : IAsyncStreamReader {
- private readonly IDictionary> _exceptionMap;
- private readonly IAsyncStreamReader _inner;
-
- public AsyncStreamReader(IDictionary> exceptionMap,
- IAsyncStreamReader inner) {
- _exceptionMap = exceptionMap;
- _inner = inner;
- }
-
- public async Task MoveNext(CancellationToken cancellationToken) {
- try {
- return await _inner.MoveNext(cancellationToken).ConfigureAwait(false);
- } catch (RpcException ex) {
- throw ConvertRpcException(ex, _exceptionMap);
- }
- }
-
- public TResponse Current => _inner.Current;
+ createdException = null;
+ return false;
+ }
+}
+
+class ExceptionConverterStreamReader(IAsyncStreamReader reader, Func convertException) : IAsyncStreamReader {
+ public TResponse Current => reader.Current;
+
+ public async Task MoveNext(CancellationToken cancellationToken) {
+ try {
+ return await reader.MoveNext(cancellationToken).ConfigureAwait(false);
+ }
+ catch (RpcException ex) {
+ throw convertException(ex);
}
}
}
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
index 213f077ff..a4de0b3a7 100644
--- a/test/Directory.Build.props
+++ b/test/Directory.Build.props
@@ -9,12 +9,12 @@
-
+
-
+
-
-
+
+
all
runtime; build; native; contentfiles; analyzers
@@ -25,6 +25,7 @@
+
diff --git a/test/EventStore.Client.Streams.Tests/Append/ShouldThrowAsyncExtensions.cs b/test/EventStore.Client.Streams.Tests/Append/ShouldThrowAsyncExtensions.cs
new file mode 100644
index 000000000..80f983ce0
--- /dev/null
+++ b/test/EventStore.Client.Streams.Tests/Append/ShouldThrowAsyncExtensions.cs
@@ -0,0 +1,14 @@
+namespace EventStore.Client.Streams.Tests.Append;
+
+public static class ShouldThrowAsyncExtensions {
+ public static Task ShouldThrowAsync(this EventStoreClient.ReadStreamResult source) where TException : Exception =>
+ source
+ .ToArrayAsync()
+ .AsTask()
+ .ShouldThrowAsync();
+
+ public static async Task ShouldThrowAsync(this EventStoreClient.ReadStreamResult source, Action handler) where TException : Exception {
+ var ex = await source.ShouldThrowAsync();
+ handler(ex);
+ }
+}
\ No newline at end of file
diff --git a/test/EventStore.Client.Streams.Tests/Append/append_to_stream.cs b/test/EventStore.Client.Streams.Tests/Append/append_to_stream.cs
new file mode 100644
index 000000000..b4ad7d49e
--- /dev/null
+++ b/test/EventStore.Client.Streams.Tests/Append/append_to_stream.cs
@@ -0,0 +1,475 @@
+using Grpc.Core;
+
+namespace EventStore.Client.Streams.Tests.Append;
+
+[Trait("Category", "Target:Stream")]
+[Trait("Category", "Operation:Append")]
+public class append_to_stream(ITestOutputHelper output, EventStoreFixture fixture) : EventStoreTests(output, fixture) {
+ public static IEnumerable