Skip to content

Commit

Permalink
Add EventStore Hosting and Client integrations (#277)
Browse files Browse the repository at this point in the history
* Add EventStore Hosting and Client integrations

* Update CODEOWNERS

* Address PR feedback

* Add client integration tests

* Update AddEventStoreTests.cs

* Add HealthCheckTimeout setting

* Remove HealthCheckTimeout from Conformance tests

* Remove Atom Pub over HTTP as support is deprecated

* Add Functional tests

* Log volume and mount can be added manually

* Remove unused const

* Update EventStoreFunctionalTests.cs

* Update EventStoreFunctionalTests.cs

* Update EventStoreFunctionalTests.cs

* Wait for resource to be healthy

* Update EventStoreFunctionalTests.cs

* Update EventStoreFunctionalTests.cs

* Fix typo

* Use Cts

* Update EventStoreFunctionalTests.cs

* Check last test

* Update EventStoreFunctionalTests.cs

* Trying all tests

* Update EventStoreFunctionalTests.cs

* Update EventStoreFunctionalTests.cs

* Update EventStoreFunctionalTests.cs

---------

Co-authored-by: Aaron Powell <[email protected]>
  • Loading branch information
fredimachado and aaronpowell authored Nov 29, 2024
1 parent dd34778 commit ea964f7
Show file tree
Hide file tree
Showing 40 changed files with 2,152 additions and 16 deletions.
9 changes: 9 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@
/examples/rust/_ @Alirexaa
/src/CommunityToolkit.Aspire.Hosting.Rust/_ @Alirexaa
/tests/CommunityToolkit.Aspire.Hosting.Rust/_ @Alirexaa

# CommunityToolkit.Aspire.EventStore
# CommunityToolkit.Aspire.Hosting.EventStore

/examples/eventstore/_ @fredimachado
/src/CommunityToolkit.Aspire.Hosting.EventStore/_ @fredimachado
/tests/CommunityToolkit.Aspire.Hosting.EventStore.Tests/_ @fredimachado
/src/CommunityToolkit.Aspire.EventStore/_ @fredimachado
/tests/CommunityToolkit.Aspire.EventStore.Tests/_ @fredimachado
84 changes: 68 additions & 16 deletions CommunityToolkit.Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hos
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.Bun.Tests", "tests\CommunityToolkit.Aspire.Hosting.Bun.Tests\CommunityToolkit.Aspire.Hosting.Bun.Tests.csproj", "{DA5DD2CB-51D9-429F-91F5-BF3D1A13A21A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eventstore", "eventstore", "{114DDF07-489A-419B-BE76-E5A289F12791}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.EventStore", "src\CommunityToolkit.Aspire.Hosting.EventStore\CommunityToolkit.Aspire.Hosting.EventStore.csproj", "{B209275E-1CFF-4AF0-A65A-2895DD679775}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.EventStore", "src\CommunityToolkit.Aspire.EventStore\CommunityToolkit.Aspire.EventStore.csproj", "{AD230A69-F6AE-4A9B-B500-90516BA2E1C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.EventStore.Tests", "tests\CommunityToolkit.Aspire.Hosting.EventStore.Tests\CommunityToolkit.Aspire.Hosting.EventStore.Tests.csproj", "{FA34A40C-62C9-4A73-A39D-53A01243657C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.EventStore.AppHost", "examples\eventstore\CommunityToolkit.Aspire.Hosting.EventStore.AppHost\CommunityToolkit.Aspire.Hosting.EventStore.AppHost.csproj", "{ED3E5B89-091C-4A0E-9A2B-946CA1A11557}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.EventStore.ServiceDefaults", "examples\eventstore\CommunityToolkit.Aspire.Hosting.EventStore.ServiceDefaults\CommunityToolkit.Aspire.Hosting.EventStore.ServiceDefaults.csproj", "{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.EventStore.ApiService", "examples\eventstore\CommunityToolkit.Aspire.Hosting.EventStore.ApiService\CommunityToolkit.Aspire.Hosting.EventStore.ApiService.csproj", "{019D6506-9D68-41AD-A7A1-A27B2FFE1253}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.EventStore.Tests", "tests\CommunityToolkit.Aspire.EventStore.Tests\CommunityToolkit.Aspire.EventStore.Tests.csproj", "{C696480B-C2E0-4ACA-BD5E-A62BF8558024}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.ActiveMQ", "src\CommunityToolkit.Aspire.Hosting.ActiveMQ\CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj", "{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "activemq", "activemq", "{BF4C4E57-DAAF-4EE5-B330-1923106BAE69}"
Expand Down Expand Up @@ -339,18 +355,6 @@ Global
{C7D057AF-E2A5-4E26-846E-A328A0F14A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7D057AF-E2A5-4E26-846E-A328A0F14A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7D057AF-E2A5-4E26-846E-A328A0F14A3C}.Release|Any CPU.Build.0 = Release|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Release|Any CPU.Build.0 = Release|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Release|Any CPU.Build.0 = Release|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Release|Any CPU.Build.0 = Release|Any CPU
{6BC98146-279F-4DE5-9B6E-0F0C07507421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BC98146-279F-4DE5-9B6E-0F0C07507421}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BC98146-279F-4DE5-9B6E-0F0C07507421}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -371,6 +375,18 @@ Global
{2CC61B84-CF97-4CE7-A08F-2EECF4AEAD92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CC61B84-CF97-4CE7-A08F-2EECF4AEAD92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CC61B84-CF97-4CE7-A08F-2EECF4AEAD92}.Release|Any CPU.Build.0 = Release|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3}.Release|Any CPU.Build.0 = Release|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C686CEA0-8B89-470B-84A2-0264040DCDC8}.Release|Any CPU.Build.0 = Release|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B825CF9-E8B8-4960-9330-648ED0323FE0}.Release|Any CPU.Build.0 = Release|Any CPU
{6095E8B8-7F99-4A12-B7E2-376F7EDD7435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6095E8B8-7F99-4A12-B7E2-376F7EDD7435}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6095E8B8-7F99-4A12-B7E2-376F7EDD7435}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -383,6 +399,34 @@ Global
{DA5DD2CB-51D9-429F-91F5-BF3D1A13A21A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA5DD2CB-51D9-429F-91F5-BF3D1A13A21A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA5DD2CB-51D9-429F-91F5-BF3D1A13A21A}.Release|Any CPU.Build.0 = Release|Any CPU
{B209275E-1CFF-4AF0-A65A-2895DD679775}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B209275E-1CFF-4AF0-A65A-2895DD679775}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B209275E-1CFF-4AF0-A65A-2895DD679775}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B209275E-1CFF-4AF0-A65A-2895DD679775}.Release|Any CPU.Build.0 = Release|Any CPU
{AD230A69-F6AE-4A9B-B500-90516BA2E1C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD230A69-F6AE-4A9B-B500-90516BA2E1C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD230A69-F6AE-4A9B-B500-90516BA2E1C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD230A69-F6AE-4A9B-B500-90516BA2E1C6}.Release|Any CPU.Build.0 = Release|Any CPU
{FA34A40C-62C9-4A73-A39D-53A01243657C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA34A40C-62C9-4A73-A39D-53A01243657C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA34A40C-62C9-4A73-A39D-53A01243657C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA34A40C-62C9-4A73-A39D-53A01243657C}.Release|Any CPU.Build.0 = Release|Any CPU
{ED3E5B89-091C-4A0E-9A2B-946CA1A11557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED3E5B89-091C-4A0E-9A2B-946CA1A11557}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED3E5B89-091C-4A0E-9A2B-946CA1A11557}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED3E5B89-091C-4A0E-9A2B-946CA1A11557}.Release|Any CPU.Build.0 = Release|Any CPU
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7}.Release|Any CPU.Build.0 = Release|Any CPU
{019D6506-9D68-41AD-A7A1-A27B2FFE1253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{019D6506-9D68-41AD-A7A1-A27B2FFE1253}.Debug|Any CPU.Build.0 = Debug|Any CPU
{019D6506-9D68-41AD-A7A1-A27B2FFE1253}.Release|Any CPU.ActiveCfg = Release|Any CPU
{019D6506-9D68-41AD-A7A1-A27B2FFE1253}.Release|Any CPU.Build.0 = Release|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C696480B-C2E0-4ACA-BD5E-A62BF8558024}.Release|Any CPU.Build.0 = Release|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -461,21 +505,29 @@ Global
{4AE83D68-EA10-473D-BD26-19C5928A8620} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{79EF8E85-1DFC-42B5-BDE3-72639F25848C} = {4AE83D68-EA10-473D-BD26-19C5928A8620}
{C7D057AF-E2A5-4E26-846E-A328A0F14A3C} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{DDDAABA3-D8F0-47C6-98E0-AB57F28404CF} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{C686CEA0-8B89-470B-84A2-0264040DCDC8} = {DDDAABA3-D8F0-47C6-98E0-AB57F28404CF}
{5B825CF9-E8B8-4960-9330-648ED0323FE0} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{6BC98146-279F-4DE5-9B6E-0F0C07507421} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{662514C8-EAED-4EAB-91CE-893D4DE2469A} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{1E753568-E34B-4E93-93F8-43764171725D} = {662514C8-EAED-4EAB-91CE-893D4DE2469A}
{FB9B8F61-5125-452B-8332-938DCFA27366} = {662514C8-EAED-4EAB-91CE-893D4DE2469A}
{373472DA-BAEB-44B6-915D-1EF3DA845797} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{79CBF217-CED1-4BB2-9A72-37D2429F83B8} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{2CC61B84-CF97-4CE7-A08F-2EECF4AEAD92} = {79CBF217-CED1-4BB2-9A72-37D2429F83B8}
{4DCF987E-9071-4899-8B5F-5FDAF2BC77D3} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{DDDAABA3-D8F0-47C6-98E0-AB57F28404CF} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{C686CEA0-8B89-470B-84A2-0264040DCDC8} = {DDDAABA3-D8F0-47C6-98E0-AB57F28404CF}
{5B825CF9-E8B8-4960-9330-648ED0323FE0} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{6095E8B8-7F99-4A12-B7E2-376F7EDD7435} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{A7614F2B-E810-412E-91E7-8B6272DD5DBB} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{36FC2579-582A-4DAF-9B20-AB33331624C6} = {A7614F2B-E810-412E-91E7-8B6272DD5DBB}
{DA5DD2CB-51D9-429F-91F5-BF3D1A13A21A} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{114DDF07-489A-419B-BE76-E5A289F12791} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{B209275E-1CFF-4AF0-A65A-2895DD679775} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{AD230A69-F6AE-4A9B-B500-90516BA2E1C6} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{FA34A40C-62C9-4A73-A39D-53A01243657C} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{ED3E5B89-091C-4A0E-9A2B-946CA1A11557} = {114DDF07-489A-419B-BE76-E5A289F12791}
{0A4E5B43-155A-4FDA-A50F-0B86CF1705E7} = {114DDF07-489A-419B-BE76-E5A289F12791}
{019D6506-9D68-41AD-A7A1-A27B2FFE1253} = {114DDF07-489A-419B-BE76-E5A289F12791}
{C696480B-C2E0-4ACA-BD5E-A62BF8558024} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
{56C3C409-10FF-4CA5-99AD-0D35C5418B2A} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
{BF4C4E57-DAAF-4EE5-B330-1923106BAE69} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
{CF6CF1C3-EBE1-41CE-9B34-0C2F931AEA12} = {BF4C4E57-DAAF-4EE5-B330-1923106BAE69}
Expand Down
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<PackageVersion Include="Aspire.Hosting.Python" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" />
<!-- AspNetCore packages -->
<PackageVersion Include="AspNetCore.HealthChecks.EventStore.gRPC" Version="8.0.1" />
<PackageVersion Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.QuickGrid" Version="$(AspNetCoreVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
Expand Down Expand Up @@ -48,6 +49,8 @@
<PackageVersion Include="Microsoft.SqlServer.DacFx" Version="162.5.57" />
<PackageVersion Include="Microsoft.Build" Version="17.11.4" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.7.8" />
<PackageVersion Include="EventStore.Client.Extensions.OpenTelemetry" Version="23.3.7" />
<PackageVersion Include="EventStore.Client.Grpc.Streams" Version="23.3.7" />
<!-- Build dependencies -->
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
<!-- Testcontainers packages -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Text.Json.Serialization;

namespace CommunityToolkit.Aspire.Hosting.EventStore.ApiService;

public class Account
{
public Guid Id { get; private set; }
public string? Name { get; private set; }
public decimal Balance { get; private set; }

[JsonIgnore]
public int Version { get; private set; } = -1;

[NonSerialized]
private readonly Queue<object> uncommittedEvents = new();

public static Account Create(Guid id, string name)
=> new(id, name);

public void Deposit(decimal amount)
{
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(amount, 0, nameof(amount));

var @event = new AccountFundsDeposited(Id, amount);

uncommittedEvents.Enqueue(@event);
Apply(@event);
}

public void Withdraw(decimal amount)
{
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(amount, 0, nameof(amount));
ArgumentOutOfRangeException.ThrowIfGreaterThan(amount, Balance, nameof(amount));

var @event = new AccountFundsWithdrew(Id, amount);

uncommittedEvents.Enqueue(@event);
Apply(@event);
}

public void When(object @event)
{
switch (@event)
{
case AccountCreated accountCreated:
Apply(accountCreated);
break;
case AccountFundsDeposited accountFundsDeposited:
Apply(accountFundsDeposited);
break;
case AccountFundsWithdrew accountFundsWithdrew:
Apply(accountFundsWithdrew);
break;
}
}

public object[] DequeueUncommittedEvents()
{
var dequeuedEvents = uncommittedEvents.ToArray();

uncommittedEvents.Clear();

return dequeuedEvents;
}

private Account()
{
}

private Account(Guid id, string name)
{
if (id == Guid.Empty)
{
throw new ArgumentException("Id cannot be empty.", nameof(id));
}
ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name));

var @event = new AccountCreated(id, name);

uncommittedEvents.Enqueue(@event);
Apply(@event);
}

private void Apply(AccountCreated @event)
{
Version++;

Id = @event.Id;
Name = @event.Name;
}

private void Apply(AccountFundsDeposited @event)
{
Version++;

Balance += @event.Amount;
}

private void Apply(AccountFundsWithdrew @event)
{
Version++;

Balance -= @event.Amount;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CommunityToolkit.Aspire.Hosting.EventStore.ApiService;

public record AccountCreated(Guid Id, string Name);

public record AccountFundsDeposited(Guid Id, decimal Amount);

public record AccountFundsWithdrew(Guid Id, decimal Amount);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.EventStore\CommunityToolkit.Aspire.EventStore.csproj" />
<ProjectReference Include="..\CommunityToolkit.Aspire.Hosting.EventStore.ServiceDefaults\CommunityToolkit.Aspire.Hosting.EventStore.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using EventStore.Client;
using System.Text.Json;
using System.Text;

namespace CommunityToolkit.Aspire.Hosting.EventStore.ApiService;

public static class EventStoreExtensions
{
public static async Task<Account?> GetAccount(this EventStoreClient eventStore, Guid id, CancellationToken cancellationToken)
{
var readResult = eventStore.ReadStreamAsync(
Direction.Forwards,
$"account-{id:N}",
StreamPosition.Start,
cancellationToken: cancellationToken
);

var readState = await readResult.ReadState;
if (readState == ReadState.StreamNotFound)
{
return null;
}

var account = (Account)Activator.CreateInstance(typeof(Account), true)!;

await foreach (var resolvedEvent in readResult)
{
var @event = resolvedEvent.Deserialize();

account.When(@event!);
}

return account;
}

public static async Task AppendAcountEvents(this EventStoreClient eventStore, Account account, CancellationToken cancellationToken)
{
var events = account.DequeueUncommittedEvents();

var eventsToAppend = events
.Select(@event => @event.Serialize()).ToArray();

var expectedVersion = account.Version - events.Length;
await eventStore.AppendToStreamAsync(
$"account-{account.Id:N}",
expectedVersion == 0 ? StreamRevision.None : StreamRevision.FromInt64(expectedVersion),
eventsToAppend,
cancellationToken: cancellationToken
);
}

private static object? Deserialize(this ResolvedEvent resolvedEvent)
{
var eventClrTypeName = JsonDocument.Parse(resolvedEvent.Event.Metadata)
.RootElement
.GetProperty("EventClrTypeName")
.GetString();

return JsonSerializer.Deserialize(
Encoding.UTF8.GetString(resolvedEvent.Event.Data.Span),
Type.GetType(eventClrTypeName!)!);
}

private static EventData Serialize(this object @event)
{
return new EventData(
Uuid.NewUuid(),
@event.GetType().Name,
data: Encoding.UTF8.GetBytes(JsonSerializer.Serialize(@event)),
metadata: Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new Dictionary<string, string>
{
{ "EventClrTypeName", @event.GetType().AssemblyQualifiedName! }
}))
);
}
}
Loading

0 comments on commit ea964f7

Please sign in to comment.