From b953380822a789a1cbede24cfc09579fd03ffa90 Mon Sep 17 00:00:00 2001 From: Tomohisa Takaoka <ttakaoka@jtechs.com> Date: Tue, 15 Aug 2023 12:28:47 -0700 Subject: [PATCH] first working sample --- Sekiban.sln | 14 +++ fsCustomerTest/Program.fs | 1 + fsCustomerTest/Tests.fs | 47 ++++++++++ fsCustomerTest/fsCustomerTest.fsproj | 34 +++++++ global.json | 7 ++ .../Shared/FeatureCheckDependency.cs | 2 +- .../Mixed.Domain/MixedContextDependency.cs | 2 +- .../Aggregates/MultiTenantDependency.cs | 2 +- samples/Shipping.Domain/ShippingDependency.cs | 2 +- .../Warehouse.Domain/WarehouseDependency.cs | 2 +- samples/fsharp/Dependency.fs | 24 +++++ samples/fsharp/Domain.fs | 92 +++++++++++++++++++ samples/fsharp/Library.fs | 5 + samples/fsharp/fsCustomer.fsproj | 24 +++++ src/Sekiban.Core/Command/CommandExecutor.cs | 4 +- .../Command/CommandHandlerAdapter.cs | 2 +- src/Sekiban.Core/Command/ICommandHandler.cs | 2 +- .../IVersionValidationCommandHandler.cs | 2 +- .../AggregateDependencyDefinition.cs | 8 +- .../DomainDependencyDefinitionBase.cs | 9 +- .../Dependency/IDependencyDefinition.cs | 1 + .../SekibanEventSourcingDependency.cs | 7 +- .../Events/RegisteredEventTypes.cs | 3 +- .../EmptyDependencyDefinition.cs | 2 +- 24 files changed, 274 insertions(+), 24 deletions(-) create mode 100644 fsCustomerTest/Program.fs create mode 100644 fsCustomerTest/Tests.fs create mode 100644 fsCustomerTest/fsCustomerTest.fsproj create mode 100644 global.json create mode 100644 samples/fsharp/Dependency.fs create mode 100644 samples/fsharp/Domain.fs create mode 100644 samples/fsharp/Library.fs create mode 100644 samples/fsharp/fsCustomer.fsproj diff --git a/Sekiban.sln b/Sekiban.sln index 2b50bada..c48210a0 100644 --- a/Sekiban.sln +++ b/Sekiban.sln @@ -57,6 +57,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Convert011To012", "tools\Co EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mixed.Test", "test\Mixed.Test\Mixed.Test.csproj", "{630F88BB-1967-4F9A-B6E2-771922069319}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "fsCustomer", "samples\fsharp\fsCustomer.fsproj", "{3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "fsCustomerTest", "fsCustomerTest\fsCustomerTest.fsproj", "{8E69545E-24E1-48D2-A0C5-5219FF2E36D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -155,6 +159,14 @@ Global {630F88BB-1967-4F9A-B6E2-771922069319}.Debug|Any CPU.Build.0 = Debug|Any CPU {630F88BB-1967-4F9A-B6E2-771922069319}.Release|Any CPU.ActiveCfg = Release|Any CPU {630F88BB-1967-4F9A-B6E2-771922069319}.Release|Any CPU.Build.0 = Release|Any CPU + {3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3}.Release|Any CPU.Build.0 = Release|Any CPU + {8E69545E-24E1-48D2-A0C5-5219FF2E36D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E69545E-24E1-48D2-A0C5-5219FF2E36D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E69545E-24E1-48D2-A0C5-5219FF2E36D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E69545E-24E1-48D2-A0C5-5219FF2E36D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -183,6 +195,8 @@ Global {091121AC-BDAB-46B3-8A49-A63D0EF6FAA5} = {B85F80AE-6A27-402C-93FA-352D938EDA8D} {482C14AE-C213-4234-9B11-F0D7E953EEE2} = {9504B5F4-E803-46E3-B110-CBA8196B03D4} {630F88BB-1967-4F9A-B6E2-771922069319} = {4C34F748-F223-44DD-899D-029F9CEF7780} + {3BDC7B2C-F56C-4EDF-AE50-D2ADCF9538A3} = {B85F80AE-6A27-402C-93FA-352D938EDA8D} + {8E69545E-24E1-48D2-A0C5-5219FF2E36D9} = {4C34F748-F223-44DD-899D-029F9CEF7780} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2DFBE53E-69A7-453A-8D20-72271AE32016} diff --git a/fsCustomerTest/Program.fs b/fsCustomerTest/Program.fs new file mode 100644 index 00000000..0695f84c --- /dev/null +++ b/fsCustomerTest/Program.fs @@ -0,0 +1 @@ +module Program = let [<EntryPoint>] main _ = 0 diff --git a/fsCustomerTest/Tests.fs b/fsCustomerTest/Tests.fs new file mode 100644 index 00000000..30f69ff5 --- /dev/null +++ b/fsCustomerTest/Tests.fs @@ -0,0 +1,47 @@ +module fsCustomerTest.Tests + +open System.Text.Json +open Sekiban.Core.Shared +open Sekiban.Testing.SingleProjections +open Xunit +open Xunit.Abstractions +open fsCustomer.Dependency +open fsCustomer.Domain + +[<Fact>] +let ``My test`` () = Assert.True(true) + + + + +type BranchSpec(testOutputHelper: ITestOutputHelper) = + inherit AggregateTest<Branch, FsCustomerDependency>() + member this.TestOutputHelper = testOutputHelper + + [<Fact>] + member this.Serialize() = + let serialized = SekibanJsonHelper.Serialize(Branch("Japan")) + this.TestOutputHelper.WriteLine(serialized) + let deserialized = SekibanJsonHelper.Deserialize<Branch>(serialized) + let serializedFromDeserialized = SekibanJsonHelper.Serialize(deserialized) + this.TestOutputHelper.WriteLine(serializedFromDeserialized) + Assert.Equal(serialized, serializedFromDeserialized) + + [<Fact>] + member this.SerializeOptionChecking() = + let options: JsonSerializerOptions = JsonSerializerOptions() + // options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + // options.PropertyNameCaseInsensitive = true + let serialized = JsonSerializer.Serialize<Branch>(Branch("Japan"), options) + this.TestOutputHelper.WriteLine(serialized) + let deserialized = JsonSerializer.Deserialize<Branch>(serialized, options) + + let serializedFromDeserialized = + JsonSerializer.Serialize<Branch>(deserialized, options) + + this.TestOutputHelper.WriteLine(serializedFromDeserialized) + Assert.Equal(serialized, serializedFromDeserialized) + + [<Fact>] + member this.CreateAggregate() = + this.WhenCommand(CreateBranch("Japan")).ThenPayloadIs(Branch("Japan")) diff --git a/fsCustomerTest/fsCustomerTest.fsproj b/fsCustomerTest/fsCustomerTest.fsproj new file mode 100644 index 00000000..8eab425b --- /dev/null +++ b/fsCustomerTest/fsCustomerTest.fsproj @@ -0,0 +1,34 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + + <IsPackable>false</IsPackable> + <GenerateProgramFile>false</GenerateProgramFile> + <IsTestProject>true</IsTestProject> + </PropertyGroup> + + <ItemGroup> + <Compile Include="Tests.fs"/> + <Compile Include="Program.fs"/> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0"/> + <PackageReference Include="xunit" Version="2.5.0"/> + <PackageReference Include="xunit.runner.visualstudio" Version="2.5.0"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + <PackageReference Include="coverlet.collector" Version="3.2.0"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\samples\fsharp\fsCustomer.fsproj"/> + <ProjectReference Include="..\src\Sekiban.Testing\Sekiban.Testing.csproj"/> + </ItemGroup> + +</Project> diff --git a/global.json b/global.json new file mode 100644 index 00000000..dad2db5e --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file diff --git a/samples/FeatureCheck.Domain/Shared/FeatureCheckDependency.cs b/samples/FeatureCheck.Domain/Shared/FeatureCheckDependency.cs index ae58ae25..45d9a14d 100644 --- a/samples/FeatureCheck.Domain/Shared/FeatureCheckDependency.cs +++ b/samples/FeatureCheck.Domain/Shared/FeatureCheckDependency.cs @@ -47,7 +47,7 @@ public class FeatureCheckDependency : DomainDependencyDefinitionBase { public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { AddAggregate<Branch>() .AddCommandHandler<CreateBranch, CreateBranch.Handler>() diff --git a/samples/Mixed.Domain/MixedContextDependency.cs b/samples/Mixed.Domain/MixedContextDependency.cs index b52503c2..118cffbc 100644 --- a/samples/Mixed.Domain/MixedContextDependency.cs +++ b/samples/Mixed.Domain/MixedContextDependency.cs @@ -8,7 +8,7 @@ public class MixedContextDependency : DomainDependencyDefinitionBase { public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { AddDependency<ShippingDependency>() .AddDependency<WarehouseDependency>(); diff --git a/samples/MultiTenant.Domain/Aggregates/MultiTenantDependency.cs b/samples/MultiTenant.Domain/Aggregates/MultiTenantDependency.cs index 3e28a35f..c4e06402 100644 --- a/samples/MultiTenant.Domain/Aggregates/MultiTenantDependency.cs +++ b/samples/MultiTenant.Domain/Aggregates/MultiTenantDependency.cs @@ -9,7 +9,7 @@ public class MultiTenantDependency : DomainDependencyDefinitionBase { public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { AddAggregate<ClientPayload>().AddCommandHandler<CreateClient, CreateClient.Handler>().AddAggregateListQuery<ClientListQuery>(); } diff --git a/samples/Shipping.Domain/ShippingDependency.cs b/samples/Shipping.Domain/ShippingDependency.cs index a279d889..cbf86a43 100644 --- a/samples/Shipping.Domain/ShippingDependency.cs +++ b/samples/Shipping.Domain/ShippingDependency.cs @@ -9,7 +9,7 @@ public class ShippingDependency : DomainDependencyDefinitionBase { public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { AddAggregate<Product>() .AddCommandHandler<CreateProduct, CreateProduct.Handler>() diff --git a/samples/Warehouse.Domain/WarehouseDependency.cs b/samples/Warehouse.Domain/WarehouseDependency.cs index c1760a74..97f5a3bf 100644 --- a/samples/Warehouse.Domain/WarehouseDependency.cs +++ b/samples/Warehouse.Domain/WarehouseDependency.cs @@ -8,7 +8,7 @@ public class WarehouseDependency : DomainDependencyDefinitionBase { public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { AddAggregate<ProductStock>() .AddCommandHandler<AddProductStock, AddProductStock.Handler>() diff --git a/samples/fsharp/Dependency.fs b/samples/fsharp/Dependency.fs new file mode 100644 index 00000000..c27acb6f --- /dev/null +++ b/samples/fsharp/Dependency.fs @@ -0,0 +1,24 @@ +module fsCustomer.Dependency + +open System.Reflection +open Sekiban.Core.Dependency +open fsCustomer.Domain + + +type FsCustomerDependency() = + inherit DomainDependencyDefinitionBase() + + override this.Define() = + do + this + .AddAggregate<Branch>() + .AddCommandHandler<CreateBranch, CreateBranchHandler>() + |> ignore + + this + .AddAggregate<Client>() + .AddCommandHandler<CreateClient, CreateClientHandler>() + .AddAggregateQuery<ClientEmailExistsQuery>() + |> ignore + + override this.GetExecutingAssembly() = Assembly.GetExecutingAssembly() diff --git a/samples/fsharp/Domain.fs b/samples/fsharp/Domain.fs new file mode 100644 index 00000000..d0816f06 --- /dev/null +++ b/samples/fsharp/Domain.fs @@ -0,0 +1,92 @@ +module fsCustomer.Domain + +open System +open System.Text.Json.Serialization +open FSharp.Control +open Sekiban.Core.Aggregate +open Sekiban.Core.Command +open Sekiban.Core.Events +open Sekiban.Core.Query.QueryModel + +type Branch [<JsonConstructor>] (name: string) = + member this.Name = name + interface IAggregatePayload + new() = Branch("") + +type CreateBranch(name: string) = + member this.Name = name + + interface ICommand<Branch> with + member this.GetAggregateId() = Guid.NewGuid() + +type BranchCreated = + { Name: string } + + interface IEventPayload<Branch, Branch, BranchCreated> with + static member OnEvent(aggregatePayload, ev) = Branch(ev.Payload.Name) + +type CreateBranchHandler() = + interface ICommandHandler<Branch, CreateBranch> with + member this.HandleCommandAsync(getAggregateState, command) = + taskSeq { yield { Name = command.Name } :> IEventPayloadApplicableTo<Branch> } + + +type Client(name: string, email: string, branchId: Guid) = + member this.Name = name + member this.Email = email + member this.BranchId = branchId + interface IAggregatePayload + new() = Client("", "", Guid.Empty) + +type CreateClient = + { Name: string + Email: string + BranchId: Guid } + + interface ICommand<Client> with + member this.GetAggregateId() = Guid.NewGuid() + +type ClientCreated = + { Name: string + Email: string + BranchId: Guid } + + interface IEventPayload<Client, Client, ClientCreated> with + static member OnEvent(aggregatePayload, ev) = + Client(ev.Payload.Name, ev.Payload.Email, ev.Payload.BranchId) + +type ClientEmailExistsQueryResponse = + { Exists: bool } + + interface IQueryResponse + +type ClientEmailExistsQueryParam = + { Email: string } + + interface IQueryParameter<ClientEmailExistsQueryResponse> + + + +type ClientEmailExistsQuery = + interface IAggregateQuery<Client, ClientEmailExistsQueryParam, ClientEmailExistsQueryResponse> with + member this.HandleFilter(queryParam, list) = + { Exists = list |> Seq.exists (fun client -> client.Payload.Email = queryParam.Email) } + +type CreateClientHandler(queryExecutor: IQueryExecutor) = + member this.QueryExecutor = queryExecutor + + interface ICommandHandler<Client, CreateClient> with + member this.HandleCommandAsync(getAggregateState, command) = + taskSeq { + let branchExistsResponse = + this.QueryExecutor.ExecuteAsync({ Email = command.Email }) + |> Async.AwaitTask + |> Async.RunSynchronously + + if branchExistsResponse.Exists then + yield + { Name = command.Name + Email = command.Email + BranchId = command.BranchId } + :> IEventPayloadApplicableTo<Client> + } diff --git a/samples/fsharp/Library.fs b/samples/fsharp/Library.fs new file mode 100644 index 00000000..8b1d2757 --- /dev/null +++ b/samples/fsharp/Library.fs @@ -0,0 +1,5 @@ +namespace fsCustomer + +module Say = + let hello name = + printfn "Hello %s" name diff --git a/samples/fsharp/fsCustomer.fsproj b/samples/fsharp/fsCustomer.fsproj new file mode 100644 index 00000000..c8cdf1d8 --- /dev/null +++ b/samples/fsharp/fsCustomer.fsproj @@ -0,0 +1,24 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + <GenerateDocumentationFile>true</GenerateDocumentationFile> + <LangVersion>default</LangVersion> + </PropertyGroup> + + <ItemGroup> + <Compile Include="Library.fs"/> + <Compile Include="Domain.fs"/> + <Compile Include="Dependency.fs"/> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\src\Sekiban.Core\Sekiban.Core.csproj"/> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="FSharp.Control.AsyncSeq" Version="3.2.1"/> + <PackageReference Include="FSharp.Control.TaskSeq" Version="0.3.0"/> + </ItemGroup> + +</Project> diff --git a/src/Sekiban.Core/Command/CommandExecutor.cs b/src/Sekiban.Core/Command/CommandExecutor.cs index 6e18691a..190fc887 100644 --- a/src/Sekiban.Core/Command/CommandExecutor.cs +++ b/src/Sekiban.Core/Command/CommandExecutor.cs @@ -90,7 +90,7 @@ public async Task<CommandExecutorResponseWithEvents> ExecCommandWithoutValidatio public async Task<(CommandExecutorResponse, List<IEvent>)> ExecCommandAsyncTyped<TAggregatePayload, TCommand>( TCommand command, - List<CallHistory>? callHistories = null) where TAggregatePayload : IAggregatePayloadCommon where TCommand : ICommand<TAggregatePayload> + List<CallHistory>? callHistories = null) where TAggregatePayload : IAggregatePayloadCommon, new() where TCommand : ICommand<TAggregatePayload> { var validationResult = command.ValidateProperties().ToList(); if (validationResult.Any()) @@ -108,7 +108,7 @@ public async Task<CommandExecutorResponseWithEvents> ExecCommandWithoutValidatio public async Task<(CommandExecutorResponse, List<IEvent>)> ExecCommandWithoutValidationAsyncTyped<TAggregatePayload, TCommand>( TCommand command, - List<CallHistory>? callHistories = null) where TAggregatePayload : IAggregatePayloadCommon where TCommand : ICommand<TAggregatePayload> + List<CallHistory>? callHistories = null) where TAggregatePayload : IAggregatePayloadCommon, new() where TCommand : ICommand<TAggregatePayload> { var rootPartitionKey = command.GetRootPartitionKey(); if (!CommandRootPartitionValidationAttribute.IsValidRootPartitionKey(rootPartitionKey)) diff --git a/src/Sekiban.Core/Command/CommandHandlerAdapter.cs b/src/Sekiban.Core/Command/CommandHandlerAdapter.cs index 7cc2cca6..64367031 100644 --- a/src/Sekiban.Core/Command/CommandHandlerAdapter.cs +++ b/src/Sekiban.Core/Command/CommandHandlerAdapter.cs @@ -9,7 +9,7 @@ namespace Sekiban.Core.Command; /// System use command handler adapter. /// Application Developer does not need to implement this interface /// </summary> -public sealed class CommandHandlerAdapter<TAggregatePayload, TCommand> where TAggregatePayload : IAggregatePayloadCommon +public sealed class CommandHandlerAdapter<TAggregatePayload, TCommand> where TAggregatePayload : IAggregatePayloadCommon, new() where TCommand : ICommand<TAggregatePayload> { private readonly IAggregateLoader _aggregateLoader; diff --git a/src/Sekiban.Core/Command/ICommandHandler.cs b/src/Sekiban.Core/Command/ICommandHandler.cs index 0b6c772e..baae1268 100644 --- a/src/Sekiban.Core/Command/ICommandHandler.cs +++ b/src/Sekiban.Core/Command/ICommandHandler.cs @@ -10,7 +10,7 @@ namespace Sekiban.Core.Command; /// <typeparam name="TAggregatePayload">Target Aggregate</typeparam> /// <typeparam name="TCommand">Target Command</typeparam> public interface ICommandHandler<TAggregatePayload, TCommand> : ICommandHandlerCommon<TAggregatePayload, TCommand> - where TAggregatePayload : IAggregatePayloadCommon where TCommand : ICommand<TAggregatePayload> + where TAggregatePayload : IAggregatePayloadCommon, new() where TCommand : ICommand<TAggregatePayload> { /// <summary> /// A Command Handler. diff --git a/src/Sekiban.Core/Command/IVersionValidationCommandHandler.cs b/src/Sekiban.Core/Command/IVersionValidationCommandHandler.cs index 0b7110f9..2e0e3765 100644 --- a/src/Sekiban.Core/Command/IVersionValidationCommandHandler.cs +++ b/src/Sekiban.Core/Command/IVersionValidationCommandHandler.cs @@ -10,4 +10,4 @@ namespace Sekiban.Core.Command; /// <typeparam name="TAggregatePayload"></typeparam> /// <typeparam name="TCommand"></typeparam> public interface IVersionValidationCommandHandler<TAggregatePayload, TCommand> : ICommandHandler<TAggregatePayload, TCommand> - where TAggregatePayload : IAggregatePayloadCommon where TCommand : IVersionValidationCommand<TAggregatePayload>; + where TAggregatePayload : IAggregatePayloadCommon, new() where TCommand : IVersionValidationCommand<TAggregatePayload>; diff --git a/src/Sekiban.Core/Dependency/AggregateDependencyDefinition.cs b/src/Sekiban.Core/Dependency/AggregateDependencyDefinition.cs index 53376aa0..c86c085e 100644 --- a/src/Sekiban.Core/Dependency/AggregateDependencyDefinition.cs +++ b/src/Sekiban.Core/Dependency/AggregateDependencyDefinition.cs @@ -88,13 +88,13 @@ public class AggregateDependencyDefinition<TAggregatePayload> : IAggregateDepend /// <summary> /// Add Command Handler to Aggregate /// </summary> - /// <typeparam name="TCreateCommand">Target Command</typeparam> + /// <typeparam name="TCommand">Target Command</typeparam> /// <typeparam name="TCommandHandler">Command Handler for Target Command</typeparam> /// <returns>Self for method chain</returns> - public AggregateDependencyDefinition<TAggregatePayload> AddCommandHandler<TCreateCommand, TCommandHandler>() - where TCreateCommand : ICommand<TAggregatePayload>, new() where TCommandHandler : ICommandHandlerCommon<TAggregatePayload, TCreateCommand> + public AggregateDependencyDefinition<TAggregatePayload> AddCommandHandler<TCommand, TCommandHandler>() + where TCommand : ICommand<TAggregatePayload> where TCommandHandler : ICommandHandlerCommon<TAggregatePayload, TCommand> { - SelfCommandTypes = SelfCommandTypes.Add((typeof(ICommandHandlerCommon<TAggregatePayload, TCreateCommand>), typeof(TCommandHandler))); + SelfCommandTypes = SelfCommandTypes.Add((typeof(ICommandHandlerCommon<TAggregatePayload, TCommand>), typeof(TCommandHandler))); return this; } /// <summary> diff --git a/src/Sekiban.Core/Dependency/DomainDependencyDefinitionBase.cs b/src/Sekiban.Core/Dependency/DomainDependencyDefinitionBase.cs index 0c9bf0dd..1843779c 100644 --- a/src/Sekiban.Core/Dependency/DomainDependencyDefinitionBase.cs +++ b/src/Sekiban.Core/Dependency/DomainDependencyDefinitionBase.cs @@ -21,11 +21,6 @@ public abstract class DomainDependencyDefinitionBase : IDependencyDefinition private ImmutableList<Type> GeneralListQueryTypes { get; set; } = ImmutableList<Type>.Empty; private ImmutableList<Assembly> Assemblies { get; set; } = ImmutableList<Assembly>.Empty; private ImmutableList<Action<IServiceCollection>> ServiceActions { get; set; } = ImmutableList<Action<IServiceCollection>>.Empty; - protected DomainDependencyDefinitionBase() - { - // ReSharper disable once VirtualMemberCallInConstructor - Define(); - } public abstract Assembly GetExecutingAssembly(); public IEnumerable<(Type serviceType, Type? implementationType)> GetCommandDependencies() @@ -73,6 +68,8 @@ public virtual SekibanDependencyOptions GetSekibanDependencyOptions() => new SekibanAggregateTypes(GetAssembliesForOptions()), GetCommandDependencies().Concat(GetSubscriberDependencies())); + public abstract void Define(); + public void AddServices(Action<IServiceCollection> serviceAction) { @@ -94,8 +91,6 @@ public IEnumerable<Type> GetSingleProjectionTypes() return AggregateDefinitions.SelectMany(s => s.SingleProjectionTypes); } - protected abstract void Define(); - public IEnumerable<Type> GetAggregatePayloadTypes() { return AggregateDefinitions.Select(s => s.AggregateType); diff --git a/src/Sekiban.Core/Dependency/IDependencyDefinition.cs b/src/Sekiban.Core/Dependency/IDependencyDefinition.cs index 4f08dcae..b4c27e10 100644 --- a/src/Sekiban.Core/Dependency/IDependencyDefinition.cs +++ b/src/Sekiban.Core/Dependency/IDependencyDefinition.cs @@ -21,4 +21,5 @@ public SekibanDependencyOptions GetSekibanDependencyOptions() => IEnumerable<(Type serviceType, Type? implementationType)> GetSubscriberDependencies(); IEnumerable<Action<IServiceCollection>> GetServiceActions(); IEnumerable<IAggregateDependencyDefinition> GetAggregateDefinitions(); + void Define(); } diff --git a/src/Sekiban.Core/Dependency/SekibanEventSourcingDependency.cs b/src/Sekiban.Core/Dependency/SekibanEventSourcingDependency.cs index ca582568..7a9167b4 100644 --- a/src/Sekiban.Core/Dependency/SekibanEventSourcingDependency.cs +++ b/src/Sekiban.Core/Dependency/SekibanEventSourcingDependency.cs @@ -48,7 +48,8 @@ public static void Register( services.AddSekibanCore(sekibanDateProducer ?? new SekibanDateProducer(), multiProjectionType, configuration); services.AddSekibanHTTPUser(); services.AddSekibanSettingsFromAppSettings(); - + // run Define() before using. + dependencyDefinition.Define(); // Each Domain contexts services.AddSingleton(dependencyDefinition.GetSekibanDependencyOptions().RegisteredEventTypes); services.AddSingleton(dependencyDefinition.GetSekibanDependencyOptions().SekibanAggregateTypes); @@ -88,6 +89,8 @@ public static void RegisterForInMemoryTest( services.AddSekibanHTTPUser(); services.AddSekibanSettingsFromAppSettings(); + // run Define() before using. + dependencyDefinition.Define(); // Each Domain contexts services.AddSingleton(dependencyDefinition.GetSekibanDependencyOptions().RegisteredEventTypes); @@ -127,6 +130,8 @@ public static void RegisterForAggregateTest( services.AddSekibanHTTPUser(); services.AddSekibanAppSettingsFromObject(new AggregateSettings()); + // run Define() before using. + dependencyDefinition.Define(); // Each Domain contexts services.AddSingleton(dependencyDefinition.GetSekibanDependencyOptions().RegisteredEventTypes); diff --git a/src/Sekiban.Core/Events/RegisteredEventTypes.cs b/src/Sekiban.Core/Events/RegisteredEventTypes.cs index ddd67ffb..d302645c 100644 --- a/src/Sekiban.Core/Events/RegisteredEventTypes.cs +++ b/src/Sekiban.Core/Events/RegisteredEventTypes.cs @@ -19,7 +19,8 @@ public RegisteredEventTypes(params Assembly[] assemblies) { foreach (var assembly in assemblies) { - var decoratedTypes = assembly.DefinedTypes.Where(x => x.IsClass && x.ImplementedInterfaces.Contains(typeof(IEventPayloadCommon))); + var types = assembly.DefinedTypes; + var decoratedTypes = types.Where(x => x.IsClass && x.ImplementedInterfaces.Contains(typeof(IEventPayloadCommon))); foreach (var type in decoratedTypes) { if (_registeredTypes.Contains(type)) diff --git a/tools/Convert011To012/EmptyDependencyDefinition.cs b/tools/Convert011To012/EmptyDependencyDefinition.cs index c6a2faaa..8abc28f3 100644 --- a/tools/Convert011To012/EmptyDependencyDefinition.cs +++ b/tools/Convert011To012/EmptyDependencyDefinition.cs @@ -13,7 +13,7 @@ public class EmptyDependencyDefinition : DomainDependencyDefinitionBase, IWebDep public SekibanControllerOptions Options => new(); public override Assembly GetExecutingAssembly() => Assembly.GetExecutingAssembly(); - protected override void Define() + public override void Define() { } }