From 14d9d8a3577a59916a46177b8f33afcccd2a111d Mon Sep 17 00:00:00 2001 From: Lucian Ghinet Date: Fri, 24 Nov 2023 16:43:11 +0200 Subject: [PATCH] v2 --- dependencies.props | 77 ++- .../ContractCommandHandlers.cs | 12 +- .../NBB.Contracts.Worker.csproj | 2 +- .../NBB.Contracts.Worker/Program.cs | 3 +- .../CreateInvoiceCommandHandler.cs | 50 +- .../MarkInvoiceAsPayedCommandHandler.cs | 3 +- .../ProcessInvoiceCommandHandler.cs | 2 +- .../NBB.Invoices.Worker.csproj | 2 +- .../NBB.Invoices.Worker/Program.cs | 2 +- .../NBB.MicroServicesOrchestration.csproj | 2 +- .../NBB.MicroServicesOrchestration/Program.cs | 2 +- .../CreatePayableCommandHandler.cs | 4 +- .../PayPayableCommandHandler.cs | 60 +- .../NBB.Payments.Worker.csproj | 2 +- .../NBB.Payments.Worker/Program.cs | 164 ++--- samples/Monolith/NBB.Mono/NBB.Mono.csproj | 2 +- samples/Monolith/NBB.Mono/Startup.cs | 200 +++--- .../Application/CreateTodoTaskHandler.cs | 5 +- .../NBB.Todo.Worker/NBB.Todo.Worker.csproj | 2 +- .../MultiTenancy/NBB.Todo.Worker/Program.cs | 2 +- .../ProcessManagerSample.csproj | 2 +- .../ProcessManagerSample/Startup.cs | 2 +- .../Mediator.cs | 170 ++--- .../Builder/MediatRMessagingHostExtensions.cs | 2 +- .../NBB.Messaging.Rusi.csproj | 86 +-- .../EventSourcedRepositoryBenchmark.cs | 588 +++++++++--------- .../EventStoreBenchmarks.csproj | 2 +- .../SnapshotStoreDBIntegrationTests.cs | 330 +++++----- .../EventSourcedRepositoryTests.cs | 577 ++++++++--------- .../MessagingHostBuilderTests.cs | 4 +- .../TenantTokenResolverConfigurationTests.cs | 14 +- .../NBB.ProjectR.Tests.csproj | 2 +- .../NBB.ProjectR.Tests/TestFixture.cs | 54 +- 33 files changed, 1210 insertions(+), 1221 deletions(-) diff --git a/dependencies.props b/dependencies.props index 9d32a4dd..6544dbcf 100644 --- a/dependencies.props +++ b/dependencies.props @@ -1,41 +1,40 @@  - - 13.0.1 - 11.1.0 - 1.0.1 - 11.0.0 - 3.3.0 - 0.13.1 - 4.16.1 - 2.4.1 - 2.4.3 - 3.1.0 - 17.0.0 - 4.1.0 - 6.3.0 - 5.0.1 - 7.0.0 - 7.0.0 - 4.7.0 - 1.5.0 - 1.5.0 - 1.5.0 - 1.0.0-rc9.14 - 1.0.0-beta.7 - 1.0.0-rc9.14 - 1.5.0 - 1.5.0-rc.1 - 1.5.0-rc.1 - 7.2.2 - 2.10.0 - 3.1.0 - 4.0.1 - 5.6.1 - 4.1.0 - 12.0.0 - 10.6.6 - 4.17.0 - 1.0.3 - 6.15.0 - + + 13.0.1 + 12.2.0 + 2.0.1 + 3.3.0 + 0.13.1 + 4.20.69 + 2.4.1 + 2.4.3 + 3.1.0 + 17.0.0 + 4.1.0 + 6.3.0 + 5.0.1 + 8.0.0 + 8.0.0 + 4.7.0 + 1.5.0 + 1.5.0 + 1.5.0 + 1.0.0-rc9.14 + 1.0.0-beta.7 + 1.0.0-rc9.14 + 1.5.0 + 1.5.0-rc.1 + 1.5.0-rc.1 + 7.2.2 + 2.10.0 + 3.1.0 + 4.0.1 + 5.6.1 + 4.1.0 + 12.0.0 + 10.6.6 + 4.17.0 + 1.0.3 + 6.15.0 + diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs index 18b2af11..d7514827 100644 --- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs +++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs @@ -27,25 +27,21 @@ public ContractCommandHandlers(IEventSourcedRepository repository, Con _logger = logger; } - public async Task Handle(CreateContract command, CancellationToken cancellationToken) + public async Task Handle(CreateContract command, CancellationToken cancellationToken) { var contract = new Contract(command.ClientId); await _repository.SaveAsync(contract, cancellationToken); _domainMetrics.ContractCreated(); - - return Unit.Value; } - public async Task Handle(AddContractLine command, CancellationToken cancellationToken) + public async Task Handle(AddContractLine command, CancellationToken cancellationToken) { var contract = await _repository.GetByIdAsync(command.ContractId, cancellationToken); contract.AddContractLine(command.Product, command.Price, command.Quantity); await _repository.SaveAsync(contract, cancellationToken); - - return Unit.Value; } - public async Task Handle(ValidateContract command, CancellationToken cancellationToken) + public async Task Handle(ValidateContract command, CancellationToken cancellationToken) { _logger.LogInformation("Validating contract"); @@ -53,8 +49,6 @@ public async Task Handle(ValidateContract command, CancellationToken cance contract.Validate(); await _repository.SaveAsync(contract, cancellationToken); _domainMetrics.ContractValidated(); - - return Unit.Value; } } } diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj index 9c1499f6..24ebe62c 100644 --- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj +++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj @@ -20,7 +20,7 @@ - + diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs index 1048aec5..7ea4c03f 100644 --- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs +++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs @@ -45,8 +45,7 @@ public static async Task Main(string[] args) }) .ConfigureServices((hostingContext, services) => { - services.AddMediatR(typeof(ContractCommandHandlers).Assembly); - + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); var transport = hostingContext.Configuration.GetValue("Messaging:Transport", "NATS"); if (transport.Equals("NATS", StringComparison.InvariantCultureIgnoreCase)) diff --git a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/CreateInvoiceCommandHandler.cs b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/CreateInvoiceCommandHandler.cs index 14e556b6..bd47811d 100644 --- a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/CreateInvoiceCommandHandler.cs +++ b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/CreateInvoiceCommandHandler.cs @@ -1,30 +1,28 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using MediatR; -using NBB.Data.Abstractions; -using NBB.Invoices.Domain.InvoiceAggregate; +using MediatR; +using NBB.Data.Abstractions; +using NBB.Invoices.Domain.InvoiceAggregate; using NBB.Invoices.PublishedLanguage; -using System.Threading; -using System.Threading.Tasks; - -namespace NBB.Invoices.Application.CommandHandlers -{ - public class CreateInvoiceCommandHandler : IRequestHandler - { - private readonly ICrudRepository _repository; - public CreateInvoiceCommandHandler(ICrudRepository repository) - { - this._repository = repository; - } - - public async Task Handle(CreateInvoice command, CancellationToken cancellationToken) - { - var invoice = new Invoice(command.ClientId, command.ContractId, command.Amount); - await _repository.AddAsync(invoice, cancellationToken); - await _repository.SaveChangesAsync(cancellationToken); - - return Unit.Value; - } - } -} +using System.Threading; +using System.Threading.Tasks; + +namespace NBB.Invoices.Application.CommandHandlers +{ + public class CreateInvoiceCommandHandler : IRequestHandler + { + private readonly ICrudRepository _repository; + public CreateInvoiceCommandHandler(ICrudRepository repository) + { + this._repository = repository; + } + + public async Task Handle(CreateInvoice command, CancellationToken cancellationToken) + { + var invoice = new Invoice(command.ClientId, command.ContractId, command.Amount); + await _repository.AddAsync(invoice, cancellationToken); + await _repository.SaveChangesAsync(cancellationToken); + } + } +} diff --git a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/MarkInvoiceAsPayedCommandHandler.cs b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/MarkInvoiceAsPayedCommandHandler.cs index e11f6424..2160a29e 100644 --- a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/MarkInvoiceAsPayedCommandHandler.cs +++ b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/MarkInvoiceAsPayedCommandHandler.cs @@ -18,7 +18,7 @@ public MarkInvoiceAsPayedCommandHandler(ICrudRepository repository) this._repository = repository; } - public async Task Handle(MarkInvoiceAsPayed command, CancellationToken cancellationToken) + public async Task Handle(MarkInvoiceAsPayed command, CancellationToken cancellationToken) { var invoice = await _repository.GetByIdAsync(command.InvoiceId, cancellationToken); if (invoice != null) @@ -27,7 +27,6 @@ public async Task Handle(MarkInvoiceAsPayed command, CancellationToken can await _repository.SaveChangesAsync(cancellationToken); } - return Unit.Value; } } } diff --git a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/ProcessInvoiceCommandHandler.cs b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/ProcessInvoiceCommandHandler.cs index 3114280b..9ef19f85 100644 --- a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/ProcessInvoiceCommandHandler.cs +++ b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Application/CommandHandlers/ProcessInvoiceCommandHandler.cs @@ -22,7 +22,7 @@ public ProcessInvoiceCommandHandler(ICrudRepository invocieRepository, this._invoiceLockRepository = invoiceLockRepository; } - public Task Handle(ProcessInvoice command, CancellationToken cancellationToken) + public Task Handle(ProcessInvoice command, CancellationToken cancellationToken) => UsingInvoiceLock(command.InvoiceId, lockTimeoutMs: 10000, async () => { var invoice = await _invocieRepository.GetByIdAsync(command.InvoiceId, cancellationToken); diff --git a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/NBB.Invoices.Worker.csproj b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/NBB.Invoices.Worker.csproj index 2b8304f2..7306d1cf 100644 --- a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/NBB.Invoices.Worker.csproj +++ b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/NBB.Invoices.Worker.csproj @@ -22,7 +22,7 @@ - + diff --git a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/Program.cs b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/Program.cs index 28747920..c3ba19ad 100644 --- a/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/Program.cs +++ b/samples/MicroServices/NBB.Invoices/NBB.Invoices.Worker/Program.cs @@ -48,7 +48,7 @@ public static async Task Main(string[] args) }) .ConfigureServices((hostingContext, services) => { - services.AddMediatR(typeof(CreateInvoiceCommandHandler).Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); services.AddMessageBus().AddNatsTransport(hostingContext.Configuration); services.AddInvoicesWriteDataAccess(); diff --git a/samples/MicroServices/NBB.MicroServicesOrchestration/NBB.MicroServicesOrchestration.csproj b/samples/MicroServices/NBB.MicroServicesOrchestration/NBB.MicroServicesOrchestration.csproj index 4b7af13f..9d2c9d01 100644 --- a/samples/MicroServices/NBB.MicroServicesOrchestration/NBB.MicroServicesOrchestration.csproj +++ b/samples/MicroServices/NBB.MicroServicesOrchestration/NBB.MicroServicesOrchestration.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/MicroServices/NBB.MicroServicesOrchestration/Program.cs b/samples/MicroServices/NBB.MicroServicesOrchestration/Program.cs index 3ef339d1..917f73b9 100644 --- a/samples/MicroServices/NBB.MicroServicesOrchestration/Program.cs +++ b/samples/MicroServices/NBB.MicroServicesOrchestration/Program.cs @@ -42,7 +42,7 @@ public static async Task Main(string[] args) }) .ConfigureServices((hostingContext, services) => { - services.AddMediatR(typeof(Program).Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); services.AddMessageBus().AddNatsTransport(hostingContext.Configuration); diff --git a/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/CreatePayableCommandHandler.cs b/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/CreatePayableCommandHandler.cs index 74769d58..1b563f60 100644 --- a/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/CreatePayableCommandHandler.cs +++ b/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/CreatePayableCommandHandler.cs @@ -20,13 +20,11 @@ public CreatePayableCommandHandler(ICrudRepository repository) _repository = repository; } - public async Task Handle(CreatePayable command, CancellationToken cancellationToken) + public async Task Handle(CreatePayable command, CancellationToken cancellationToken) { var payable = new Payable(command.ClientId, command.Amount, command.InvoiceId, command.ContractId); await _repository.AddAsync(payable, cancellationToken); await _repository.SaveChangesAsync(cancellationToken); - - return Unit.Value; } } diff --git a/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/PayPayableCommandHandler.cs b/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/PayPayableCommandHandler.cs index 6b655282..6ea18ec7 100644 --- a/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/PayPayableCommandHandler.cs +++ b/samples/MicroServices/NBB.Payments/NBB.Payments.Application/CommandHandlers/PayPayableCommandHandler.cs @@ -1,35 +1,33 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using MediatR; -using NBB.Data.Abstractions; -using NBB.Payments.Domain.PayableAggregate; +using MediatR; +using NBB.Data.Abstractions; +using NBB.Payments.Domain.PayableAggregate; using NBB.Payments.PublishedLanguage; -using System.Threading; -using System.Threading.Tasks; - -namespace NBB.Payments.Application.CommandHandlers -{ - public class PayPayableCommandHandler : IRequestHandler - { - private readonly ICrudRepository _repository; - - public PayPayableCommandHandler(ICrudRepository repository) - { - _repository = repository; - } - - - public async Task Handle(PayPayable command, CancellationToken cancellationToken) - { - var payable = await _repository.GetByIdAsync(command.PayableId, cancellationToken); - if (payable != null) - { - payable.Pay(); - await _repository.SaveChangesAsync(cancellationToken); - } - - return Unit.Value; - } - } -} +using System.Threading; +using System.Threading.Tasks; + +namespace NBB.Payments.Application.CommandHandlers +{ + public class PayPayableCommandHandler : IRequestHandler + { + private readonly ICrudRepository _repository; + + public PayPayableCommandHandler(ICrudRepository repository) + { + _repository = repository; + } + + + public async Task Handle(PayPayable command, CancellationToken cancellationToken) + { + var payable = await _repository.GetByIdAsync(command.PayableId, cancellationToken); + if (payable != null) + { + payable.Pay(); + await _repository.SaveChangesAsync(cancellationToken); + } + } + } +} diff --git a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/NBB.Payments.Worker.csproj b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/NBB.Payments.Worker.csproj index 3cc506cc..dbce973c 100644 --- a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/NBB.Payments.Worker.csproj +++ b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/NBB.Payments.Worker.csproj @@ -22,7 +22,7 @@ - + diff --git a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/Program.cs b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/Program.cs index 68b17ac0..e9721068 100644 --- a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/Program.cs +++ b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/Program.cs @@ -1,89 +1,89 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using MediatR; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NBB.Application.MediatR; -using NBB.Core.Abstractions; -using NBB.Correlation.Serilog; -using NBB.Domain; -using NBB.Domain.Abstractions; -using NBB.EventStore.Abstractions; -using NBB.Messaging.Host; -using NBB.Payments.Application.CommandHandlers; -using NBB.Payments.Data; -using Serilog; -using Serilog.Events; -using Serilog.Sinks.MSSqlServer; -using System.Threading; -using System.Threading.Tasks; - -namespace NBB.Payments.Worker -{ - public class Program - { - public static async Task Main(string[] args) - { - var builder = Host - .CreateDefaultBuilder(args) - .ConfigureLogging((hostingContext, loggingBuilder) => - { - var connectionString = hostingContext.Configuration.GetConnectionString("Logs"); - - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .Enrich.FromLogContext() - .Enrich.With() - .WriteTo.MSSqlServer(connectionString, - new MSSqlServerSinkOptions {TableName = "Logs", AutoCreateSqlTable = true}) - .CreateLogger(); - - loggingBuilder.AddSerilog(dispose: true); - loggingBuilder.AddFilter("Microsoft", logLevel => logLevel >= LogLevel.Warning); - loggingBuilder.AddConsole(); - }) - .ConfigureServices((hostingContext, services) => - { - services.AddMediatR(typeof(PayPayableCommandHandler).Assembly); - //services.AddKafkaMessaging(); - services.AddMessageBus().AddNatsTransport(hostingContext.Configuration); - - services.AddPaymentsWriteDataAccess(); - +using MediatR; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NBB.Application.MediatR; +using NBB.Core.Abstractions; +using NBB.Correlation.Serilog; +using NBB.Domain; +using NBB.Domain.Abstractions; +using NBB.EventStore.Abstractions; +using NBB.Messaging.Host; +using NBB.Payments.Application.CommandHandlers; +using NBB.Payments.Data; +using Serilog; +using Serilog.Events; +using Serilog.Sinks.MSSqlServer; +using System.Threading; +using System.Threading.Tasks; + +namespace NBB.Payments.Worker +{ + public class Program + { + public static async Task Main(string[] args) + { + var builder = Host + .CreateDefaultBuilder(args) + .ConfigureLogging((hostingContext, loggingBuilder) => + { + var connectionString = hostingContext.Configuration.GetConnectionString("Logs"); + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .Enrich.FromLogContext() + .Enrich.With() + .WriteTo.MSSqlServer(connectionString, + new MSSqlServerSinkOptions {TableName = "Logs", AutoCreateSqlTable = true}) + .CreateLogger(); + + loggingBuilder.AddSerilog(dispose: true); + loggingBuilder.AddFilter("Microsoft", logLevel => logLevel >= LogLevel.Warning); + loggingBuilder.AddConsole(); + }) + .ConfigureServices((hostingContext, services) => + { + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); + //services.AddKafkaMessaging(); + services.AddMessageBus().AddNatsTransport(hostingContext.Configuration); + + services.AddPaymentsWriteDataAccess(); + services.AddEventStore(es => { es.UseNewtownsoftJson(new SingleValueObjectConverter()); es.UseAdoNetEventRepository(opts => opts.FromConfiguration()); - }); - - services.AddMessagingHost( - hostingContext.Configuration, - hostBuilder => hostBuilder - .Configure(configBuilder => configBuilder - .AddSubscriberServices(subscriberBuilder => subscriberBuilder - .FromMediatRHandledCommands().AddAllClasses() - .FromMediatRHandledEvents().AddAllClasses() - ) - .WithDefaultOptions() - .UsePipeline(pipelineBuilder => pipelineBuilder - .UseCorrelationMiddleware() - .UseExceptionHandlingMiddleware() - .UseDefaultResiliencyMiddleware() - .UseMediatRMiddleware() - ) - )); - - services - .Decorate(typeof(IUow<>), typeof(DomainUowDecorator<>)) - .Decorate(typeof(IUow<>), typeof(MediatorUowDecorator<>)) - .Decorate(typeof(IUow<>), typeof(EventStoreUowDecorator<>)); - }); - - await builder.RunConsoleAsync(CancellationToken.None); - } - } -} + }); + + services.AddMessagingHost( + hostingContext.Configuration, + hostBuilder => hostBuilder + .Configure(configBuilder => configBuilder + .AddSubscriberServices(subscriberBuilder => subscriberBuilder + .FromMediatRHandledCommands().AddAllClasses() + .FromMediatRHandledEvents().AddAllClasses() + ) + .WithDefaultOptions() + .UsePipeline(pipelineBuilder => pipelineBuilder + .UseCorrelationMiddleware() + .UseExceptionHandlingMiddleware() + .UseDefaultResiliencyMiddleware() + .UseMediatRMiddleware() + ) + )); + + services + .Decorate(typeof(IUow<>), typeof(DomainUowDecorator<>)) + .Decorate(typeof(IUow<>), typeof(MediatorUowDecorator<>)) + .Decorate(typeof(IUow<>), typeof(EventStoreUowDecorator<>)); + }); + + await builder.RunConsoleAsync(CancellationToken.None); + } + } +} diff --git a/samples/Monolith/NBB.Mono/NBB.Mono.csproj b/samples/Monolith/NBB.Mono/NBB.Mono.csproj index 1cd296e6..2ff22bda 100644 --- a/samples/Monolith/NBB.Mono/NBB.Mono.csproj +++ b/samples/Monolith/NBB.Mono/NBB.Mono.csproj @@ -18,7 +18,7 @@ - + diff --git a/samples/Monolith/NBB.Mono/Startup.cs b/samples/Monolith/NBB.Mono/Startup.cs index a9e83c0d..16f8e221 100644 --- a/samples/Monolith/NBB.Mono/Startup.cs +++ b/samples/Monolith/NBB.Mono/Startup.cs @@ -1,111 +1,111 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using NBB.Application.MediatR; -using NBB.Contracts.Application.CommandHandlers; -using NBB.Contracts.ReadModel.Data; -using NBB.Contracts.WriteModel.Data; -using NBB.Core.Abstractions; -using NBB.Correlation.AspNet; -using NBB.Domain.Abstractions; -using NBB.EventStore.Abstractions; -using NBB.Invoices.Application.CommandHandlers; -using NBB.Invoices.Data; -using NBB.Payments.Application.CommandHandlers; -using NBB.Payments.Data; -using NBB.Domain; -using NBB.Messaging.Host; -using Microsoft.Extensions.Hosting; -using System.Linq; -using MicroServicesOrchestration; -using NBB.Core.DependencyInjection; - -namespace NBB.Mono -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddMvc(); - services.AddSingleton(Configuration); - services.AddMediatR( - typeof(ContractCommandHandlers).Assembly, - typeof(CreateInvoiceCommandHandler).Assembly, - typeof(PayPayableCommandHandler).Assembly); - - services.AddMessageBus().AddInProcessTransport(); - - services.AddContractsWriteModelDataAccess(); - services.AddContractsReadModelDataAccess(); - services.AddInvoicesDataAccess(); - services.AddPaymentsDataAccess(); - +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using NBB.Application.MediatR; +using NBB.Contracts.Application.CommandHandlers; +using NBB.Contracts.ReadModel.Data; +using NBB.Contracts.WriteModel.Data; +using NBB.Core.Abstractions; +using NBB.Correlation.AspNet; +using NBB.Domain.Abstractions; +using NBB.EventStore.Abstractions; +using NBB.Invoices.Application.CommandHandlers; +using NBB.Invoices.Data; +using NBB.Payments.Application.CommandHandlers; +using NBB.Payments.Data; +using NBB.Domain; +using NBB.Messaging.Host; +using Microsoft.Extensions.Hosting; +using System.Linq; +using MicroServicesOrchestration; +using NBB.Core.DependencyInjection; + +namespace NBB.Mono +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc(); + services.AddSingleton(Configuration); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies( + typeof(ContractCommandHandlers).Assembly, + typeof(CreateInvoiceCommandHandler).Assembly, + typeof(PayPayableCommandHandler).Assembly)); + + services.AddMessageBus().AddInProcessTransport(); + + services.AddContractsWriteModelDataAccess(); + services.AddContractsReadModelDataAccess(); + services.AddInvoicesDataAccess(); + services.AddPaymentsDataAccess(); + services.AddEventStore(es => { es.UseNewtownsoftJson(new SingleValueObjectConverter()); es.UseAdoNetEventRepository(opts => opts.FromConfiguration()); - }); - + }); + var integrationMessageAssemblies = new[] { typeof(NBB.Contracts.PublishedLanguage.ContractValidated).Assembly, typeof(NBB.Invoices.PublishedLanguage.InvoiceCreated).Assembly, typeof(NBB.Payments.PublishedLanguage.PayableCreated).Assembly, - }; - - services.AddMessagingHost( - Configuration, - hostBuilder => hostBuilder - .Configure(configBuilder => configBuilder - .AddSubscriberServices(subscriberBuiler => subscriberBuiler - .FromMediatRHandledCommands().AddClassesWhere(t => integrationMessageAssemblies.Contains(t.Assembly)) - .FromMediatRHandledEvents().AddClassesWhere(t => integrationMessageAssemblies.Contains(t.Assembly)) - ) - .WithDefaultOptions() - .UsePipeline(pipelineBuilder => pipelineBuilder - .UseExceptionHandlingMiddleware() - .UseCorrelationMiddleware() - .UseDefaultResiliencyMiddleware() - .UseMediatRMiddleware() - ) - ) - ); - - services.AddProcessManager(typeof(InvoicingProcessManager).Assembly); - - services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(DomainUowDecorator<>), - serviceType => typeof(IEventedAggregateRoot).IsAssignableFrom(serviceType.GetGenericArguments()[0])); - services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(MediatorUowDecorator<>), - serviceType => typeof(IEventedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0])); - services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(EventStoreUowDecorator<>), - serviceType => typeof(IEventedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0]) && - typeof(IIdentifiedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0])); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseCorrelation(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); - } - } -} + }; + + services.AddMessagingHost( + Configuration, + hostBuilder => hostBuilder + .Configure(configBuilder => configBuilder + .AddSubscriberServices(subscriberBuiler => subscriberBuiler + .FromMediatRHandledCommands().AddClassesWhere(t => integrationMessageAssemblies.Contains(t.Assembly)) + .FromMediatRHandledEvents().AddClassesWhere(t => integrationMessageAssemblies.Contains(t.Assembly)) + ) + .WithDefaultOptions() + .UsePipeline(pipelineBuilder => pipelineBuilder + .UseExceptionHandlingMiddleware() + .UseCorrelationMiddleware() + .UseDefaultResiliencyMiddleware() + .UseMediatRMiddleware() + ) + ) + ); + + services.AddProcessManager(typeof(InvoicingProcessManager).Assembly); + + services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(DomainUowDecorator<>), + serviceType => typeof(IEventedAggregateRoot).IsAssignableFrom(serviceType.GetGenericArguments()[0])); + services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(MediatorUowDecorator<>), + serviceType => typeof(IEventedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0])); + services.DecorateOpenGenericWhen(typeof(IUow<>), typeof(EventStoreUowDecorator<>), + serviceType => typeof(IEventedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0]) && + typeof(IIdentifiedEntity).IsAssignableFrom(serviceType.GetGenericArguments()[0])); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCorrelation(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} diff --git a/samples/MultiTenancy/NBB.Todo.Worker/Application/CreateTodoTaskHandler.cs b/samples/MultiTenancy/NBB.Todo.Worker/Application/CreateTodoTaskHandler.cs index aee3a66e..72275265 100644 --- a/samples/MultiTenancy/NBB.Todo.Worker/Application/CreateTodoTaskHandler.cs +++ b/samples/MultiTenancy/NBB.Todo.Worker/Application/CreateTodoTaskHandler.cs @@ -19,7 +19,7 @@ public CreateTodoTaskHandler(ICrudRepository todoTaskRepository) _todoTaskRepository = todoTaskRepository; } - public async Task Handle(CreateTodoTask request, CancellationToken cancellationToken) + public async Task Handle(CreateTodoTask request, CancellationToken cancellationToken) { //throw new System.Exception("handler exception"); var todoTask = new TodoTask @@ -30,10 +30,7 @@ public async Task Handle(CreateTodoTask request, CancellationToken cancell }; await _todoTaskRepository.AddAsync(todoTask, cancellationToken); - await _todoTaskRepository.SaveChangesAsync(cancellationToken); - - return Unit.Value; } } } diff --git a/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj b/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj index 1eb1482a..7583bcef 100644 --- a/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj +++ b/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj @@ -24,7 +24,7 @@ - + diff --git a/samples/MultiTenancy/NBB.Todo.Worker/Program.cs b/samples/MultiTenancy/NBB.Todo.Worker/Program.cs index 8711002a..36efb9f0 100644 --- a/samples/MultiTenancy/NBB.Todo.Worker/Program.cs +++ b/samples/MultiTenancy/NBB.Todo.Worker/Program.cs @@ -72,7 +72,7 @@ public static IHost BuildConsoleHost(string[] args) => private static void ConfigureServices(HostBuilderContext hostingContext, IServiceCollection services) { // MediatR - services.AddMediatR(typeof(CreateTodoTaskHandler).Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); // Data services.AddTodoDataAccess(); diff --git a/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj b/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj index c63952ab..50b70c87 100644 --- a/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj +++ b/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj @@ -9,7 +9,7 @@ - + diff --git a/samples/Orchestration/ProcessManagerSample/Startup.cs b/samples/Orchestration/ProcessManagerSample/Startup.cs index bc412a4a..a880eb9f 100644 --- a/samples/Orchestration/ProcessManagerSample/Startup.cs +++ b/samples/Orchestration/ProcessManagerSample/Startup.cs @@ -20,7 +20,7 @@ public static void ConfigureServicesDelegate(HostBuilderContext context, IServic services.AddMessageBus().AddInProcessTransport(); - services.AddMediatR(typeof(GetPartnerQuery).Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); //services.AddScoped, TimeoutOccuredHandler>(); diff --git a/src/Application/NBB.Application.MediatR.Effects/Mediator.cs b/src/Application/NBB.Application.MediatR.Effects/Mediator.cs index 35d91cf0..3ab9d7bc 100644 --- a/src/Application/NBB.Application.MediatR.Effects/Mediator.cs +++ b/src/Application/NBB.Application.MediatR.Effects/Mediator.cs @@ -1,88 +1,88 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using System.Threading; -using System.Threading.Tasks; -using MediatR; -using NBB.Core.Effects; -using Unit = NBB.Core.Effects.Unit; - -namespace NBB.Application.MediatR.Effects -{ - public static class MediatorEffects - { - public class Send - { - public class SideEffect : ISideEffect, IAmHandledBy> - { - public IRequest Query { get; } - - public SideEffect(IRequest query) - { - Query = query; - } - } - - - public class Handler : ISideEffectHandler, TResponse> - { - private readonly IMediator _mediator; - - public Handler(IMediator mediator) - { - _mediator = mediator; - } - - public Task Handle(SideEffect sideEffect, CancellationToken cancellationToken = default) - { - return _mediator.Send(sideEffect.Query, cancellationToken); - } - } - } - - public class Publish - { - public class SideEffect : ISideEffect - { - public INotification Notification { get; } - - public SideEffect(INotification notification) - { - Notification = notification; - } - } - - - public class Handler : ISideEffectHandler - { - private readonly IMediator _mediator; - - public Handler(IMediator mediator) - { - _mediator = mediator; - } - - public async Task Handle(SideEffect sideEffect, CancellationToken cancellationToken = default) - { - await _mediator.Publish(sideEffect.Notification, cancellationToken); - return Unit.Value; - } - } - } - } - - public static class Mediator - { - public static Effect Send(IRequest query) => - Effect.Of, TResponse>( - new MediatorEffects.Send.SideEffect(query)); - - public static Effect Send(IRequest cmd) => - Effect.Of, global::MediatR.Unit>( - new MediatorEffects.Send.SideEffect(cmd)).ToUnit(); - - public static Effect Publish(INotification notification) => - Effect.Of(new MediatorEffects.Publish.SideEffect(notification)); - - } -} +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using NBB.Core.Effects; +using Unit = NBB.Core.Effects.Unit; + +namespace NBB.Application.MediatR.Effects +{ + public static class MediatorEffects + { + public class Send + { + public class SideEffect : ISideEffect, IAmHandledBy> + { + public IRequest Query { get; } + + public SideEffect(IRequest query) + { + Query = query; + } + } + + + public class Handler : ISideEffectHandler, TResponse> + { + private readonly IMediator _mediator; + + public Handler(IMediator mediator) + { + _mediator = mediator; + } + + public Task Handle(SideEffect sideEffect, CancellationToken cancellationToken = default) + { + return _mediator.Send(sideEffect.Query, cancellationToken); + } + } + } + + public class Publish + { + public class SideEffect : ISideEffect + { + public INotification Notification { get; } + + public SideEffect(INotification notification) + { + Notification = notification; + } + } + + + public class Handler : ISideEffectHandler + { + private readonly IMediator _mediator; + + public Handler(IMediator mediator) + { + _mediator = mediator; + } + + public async Task Handle(SideEffect sideEffect, CancellationToken cancellationToken = default) + { + await _mediator.Publish(sideEffect.Notification, cancellationToken); + return Unit.Value; + } + } + } + } + + public static class Mediator + { + public static Effect Send(IRequest query) => + Effect.Of, TResponse>( + new MediatorEffects.Send.SideEffect(query)); + + //public static Effect Send(IRequest cmd) => + // Effect.Of, global::MediatR.Unit>( + // new MediatorEffects.Send.SideEffect(cmd)).ToUnit(); + + public static Effect Publish(INotification notification) => + Effect.Of(new MediatorEffects.Publish.SideEffect(notification)); + + } +} diff --git a/src/Messaging/NBB.Messaging.Host/Builder/MediatRMessagingHostExtensions.cs b/src/Messaging/NBB.Messaging.Host/Builder/MediatRMessagingHostExtensions.cs index fe0a58d6..0d3ce25a 100644 --- a/src/Messaging/NBB.Messaging.Host/Builder/MediatRMessagingHostExtensions.cs +++ b/src/Messaging/NBB.Messaging.Host/Builder/MediatRMessagingHostExtensions.cs @@ -18,7 +18,7 @@ public static class MediatorMessagingHostBuilderExtensions private record TypeInfo(Type GenericTypeDef, Func Condition); private static readonly TypeInfo EventType = new(typeof(INotificationHandler<>), _ => true); - private static readonly TypeInfo CommandType = new(typeof(IRequestHandler<,>), types => types[1] == typeof(Unit)); + private static readonly TypeInfo CommandType = new(typeof(IRequestHandler<>), _ => true); private static readonly TypeInfo QueryType = new(typeof(IRequestHandler<,>), types => types[1] != typeof(Unit)); /// diff --git a/src/Messaging/NBB.Messaging.Rusi/NBB.Messaging.Rusi.csproj b/src/Messaging/NBB.Messaging.Rusi/NBB.Messaging.Rusi.csproj index a9e2de2e..e841b7cf 100644 --- a/src/Messaging/NBB.Messaging.Rusi/NBB.Messaging.Rusi.csproj +++ b/src/Messaging/NBB.Messaging.Rusi/NBB.Messaging.Rusi.csproj @@ -1,46 +1,46 @@  - - SAK - SAK - SAK - SAK - - - - net8.0 - Rusi client transport - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - <_Parameter1>$(AssemblyName).Tests - - + + SAK + SAK + SAK + SAK + + + + net8.0 + Rusi client transport + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + <_Parameter1>$(AssemblyName).Tests + + diff --git a/test/Benchmarks/EventStoreBenchmarks/EventSourcedRepositoryBenchmark.cs b/test/Benchmarks/EventStoreBenchmarks/EventSourcedRepositoryBenchmark.cs index cdf419e3..a87fae45 100644 --- a/test/Benchmarks/EventStoreBenchmarks/EventSourcedRepositoryBenchmark.cs +++ b/test/Benchmarks/EventStoreBenchmarks/EventSourcedRepositoryBenchmark.cs @@ -1,316 +1,316 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using BenchmarkDotNet.Attributes; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using NBB.Core.Abstractions; -using NBB.EventStore.AdoNet.Migrations; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using NBB.Data.Abstractions; -using NBB.Domain; +using BenchmarkDotNet.Attributes; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using NBB.Core.Abstractions; +using NBB.EventStore.AdoNet.Migrations; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NBB.Data.Abstractions; +using NBB.Domain; using System.Reflection; using MediatR; -namespace TheBenchmarks -{ - //[SimpleJob(runStrategy:RunStrategy.ColdStart, launchCount: 2, warmupCount: 0, targetCount: 5)] - //[SimpleJob(runStrategy:RunStrategy.ColdStart, launchCount: 10, warmupCount: 0, targetCount: 1)] - [SimpleJob(launchCount: 1, warmupCount: 0, targetCount: 10)] - [RPlotExporter, RankColumn] - public class EventSourcedRepositoryBenchmark - { - private IServiceProvider _container; +namespace TheBenchmarks +{ + //[SimpleJob(runStrategy:RunStrategy.ColdStart, launchCount: 2, warmupCount: 0, targetCount: 5)] + //[SimpleJob(runStrategy:RunStrategy.ColdStart, launchCount: 10, warmupCount: 0, targetCount: 1)] + [SimpleJob(launchCount: 1, warmupCount: 0, targetCount: 10)] + [RPlotExporter, RankColumn] + public class EventSourcedRepositoryBenchmark + { + private IServiceProvider _container; private TestAggregate _loadedAggregate; - private readonly Guid _loadTestAggregateId = Guid.NewGuid(); - - private const int _snapshotFrequency = 10; - private const bool _useJunkData = false; - private const int _junkDataAggregates = 100; - private const int _junkDataEventsPerAggregate = 1000; - - [Params(10, 100, 1000)] - public int NumberOfEvents { get; set; } - - public void GlobalSetup(bool withSnapshot) - { - MigrateNBBEventStore(); - - _container = BuildServiceProvider(services => - { - services.AddEventSourcingDataAccess((sp, builder) => builder.Options.DefaultSnapshotVersionFrequency = _snapshotFrequency); - - if (withSnapshot) - services.AddEventSourcedRepository(); - else - services.AddEventSourcedRepository(); - }); - - if (withSnapshot) - SeedEventRepository(_useJunkData); - else - SeedEventRepository(_useJunkData); - } - - [GlobalSetup(Target = nameof(LoadAggregateWithoutSnapshot))] - public void GlobalSetupLoadAggregateWithoutSnapshot() - { - GlobalSetup(false); - //LoadAggregate(); - //TryLoadRandomAggregate(); - } - - [GlobalSetup(Target = nameof(LoadAndSaveAggregateWithoutSnapshot))] - public void GlobalSetupLoadAndSaveAggregateWithoutSnapshot() - { - GlobalSetup(false); - //LoadAndSaveAggregateWithoutSnapshot(); - } - - [GlobalSetup(Target = nameof(SaveAggregateWithoutSnapshot))] - public void GlobalSetupSaveAggregateWithoutSnapshot() - { - GlobalSetup(false); - } - - [GlobalSetup(Target = nameof(LoadAggregateWithSnapshot))] - public void GlobalSetupLoadAggregateWithSnapshot() - { - GlobalSetup(true); - //LoadAggregate(); - //TryLoadRandomAggregate(); + private readonly Guid _loadTestAggregateId = Guid.NewGuid(); + + private const int _snapshotFrequency = 10; + private const bool _useJunkData = false; + private const int _junkDataAggregates = 100; + private const int _junkDataEventsPerAggregate = 1000; + + [Params(10, 100, 1000)] + public int NumberOfEvents { get; set; } + + public void GlobalSetup(bool withSnapshot) + { + MigrateNBBEventStore(); + + _container = BuildServiceProvider(services => + { + services.AddEventSourcingDataAccess((sp, builder) => builder.Options.DefaultSnapshotVersionFrequency = _snapshotFrequency); + + if (withSnapshot) + services.AddEventSourcedRepository(); + else + services.AddEventSourcedRepository(); + }); + + if (withSnapshot) + SeedEventRepository(_useJunkData); + else + SeedEventRepository(_useJunkData); } - [GlobalSetup(Target = nameof(LoadAndSaveAggregateWithSnapshot))] - public void GlobalSetupLoadAndSaveAggregateWithSnapshot() - { - GlobalSetup(true); - //LoadAndSaveAggregateWithSnapshot(); - } - - [GlobalSetup(Target = nameof(SaveAggregateWithSnapshot))] - public void GlobalSetupSaveAggregateWithSnapshot() - { - GlobalSetup(true); + [GlobalSetup(Target = nameof(LoadAggregateWithoutSnapshot))] + public void GlobalSetupLoadAggregateWithoutSnapshot() + { + GlobalSetup(false); + //LoadAggregate(); + //TryLoadRandomAggregate(); + } + + [GlobalSetup(Target = nameof(LoadAndSaveAggregateWithoutSnapshot))] + public void GlobalSetupLoadAndSaveAggregateWithoutSnapshot() + { + GlobalSetup(false); + //LoadAndSaveAggregateWithoutSnapshot(); + } + + [GlobalSetup(Target = nameof(SaveAggregateWithoutSnapshot))] + public void GlobalSetupSaveAggregateWithoutSnapshot() + { + GlobalSetup(false); + } + + [GlobalSetup(Target = nameof(LoadAggregateWithSnapshot))] + public void GlobalSetupLoadAggregateWithSnapshot() + { + GlobalSetup(true); + //LoadAggregate(); + //TryLoadRandomAggregate(); + } + + [GlobalSetup(Target = nameof(LoadAndSaveAggregateWithSnapshot))] + public void GlobalSetupLoadAndSaveAggregateWithSnapshot() + { + GlobalSetup(true); + //LoadAndSaveAggregateWithSnapshot(); + } + + [GlobalSetup(Target = nameof(SaveAggregateWithSnapshot))] + public void GlobalSetupSaveAggregateWithSnapshot() + { + GlobalSetup(true); } //[Benchmark] - public void LoadAggregateWithoutSnapshot() - { - LoadAggregate(); - } - - //[Benchmark] - public void LoadAggregateWithSnapshot() - { - LoadAggregate(); - } - - [Benchmark] - public void LoadAndSaveAggregateWithSnapshot() - { - var aggregate = LoadAggregate(); - SaveAggregate(aggregate); - } - - [Benchmark] - public void LoadAndSaveAggregateWithoutSnapshot() - { - var aggregate = LoadAggregate(); - SaveAggregate(aggregate); - } - - //[Benchmark] - public void SaveAggregateWithSnapshot() - { - SaveAggregate((TestSnapshotAggregate)_loadedAggregate); - } - - //[Benchmark] - public void SaveAggregateWithoutSnapshot() - { - SaveAggregate(_loadedAggregate); - } - - public TAggregateRoot LoadAggregate() where TAggregateRoot : TestAggregate - { - using var scope = _container.CreateScope(); - var repository = scope.ServiceProvider.GetService>(); - var aggregate = repository.GetByIdAsync(_loadTestAggregateId, default).GetAwaiter().GetResult(); - - if (aggregate?.AggregateId == default(Guid)) - aggregate.AggregateId = _loadTestAggregateId; - - return aggregate; - } - - public void TryLoadRandomAggregate() where TAggregateRoot : TestAggregate - { - using var scope = _container.CreateScope(); - var repository = scope.ServiceProvider.GetService>(); - var aggregate = repository.GetByIdAsync(Guid.NewGuid(), default).GetAwaiter().GetResult(); - } - - public void SaveAggregate(TAggregateRoot aggregate) where TAggregateRoot : TestAggregate, new() - { - using var scope = _container.CreateScope(); - var repository = scope.ServiceProvider.GetService>(); - aggregate.DoAction($"Event {Guid.NewGuid()}"); - aggregate.DoAction($"Event {Guid.NewGuid()}"); - repository.SaveAsync(aggregate).GetAwaiter().GetResult(); - _loadedAggregate = aggregate; - } - - private void SeedEventRepository(bool useJunkData = false) where TAggregateRoot : TestAggregate, new() - { - if (useJunkData) - { - SeedJunkData(); - } - - SeedAggregates(NumberOfEvents, _loadTestAggregateId); - } - - private void SeedJunkData() where TAggregateRoot : TestAggregate, new() - { - var aggregateIds = Enumerable.Range(0, _junkDataAggregates).Select(x => Guid.NewGuid()).ToArray(); - - SeedAggregates(_junkDataEventsPerAggregate, aggregateIds); - } - - private void SeedAggregates(int eventNo, params Guid[] aggregateIds) where TAggregateRoot : TestAggregate, new() - { - using var scope = _container.CreateScope(); - var repository = scope.ServiceProvider.GetService>(); - - foreach (var aggregateId in aggregateIds) - { - var aggregate = new TAggregateRoot() { AggregateId = aggregateId }; - for (int i = 0; i < eventNo; i++) - { - aggregate.DoAction($"Value {i + 1}"); - - if ((i + 1) % _snapshotFrequency == 0) - repository.SaveAsync(aggregate).GetAwaiter().GetResult(); - } - - repository.SaveAsync(aggregate).GetAwaiter().GetResult(); - - aggregate.DoAction($"AdditionlValue 1"); - aggregate.DoAction($"AdditionlValue 2"); - aggregate.DoAction($"AdditionlValue 3"); - - repository.SaveAsync(aggregate).GetAwaiter().GetResult(); - - if (aggregateId == _loadTestAggregateId) - _loadedAggregate = aggregate; - } - } - - private static void MigrateNBBEventStore() - { - new AdoNetEventStoreDatabaseMigrator().ReCreateDatabaseObjects(default).Wait(); - } - - private static TestEvent GetATestEvent() - { - return new TestEvent("Lorem ipsum"); - } - - private static IServiceProvider BuildServiceProvider(Action addEventStoreAction) - { - var configurationBuilder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - - var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); - var isDevelopment = string.Equals(environment, "development", StringComparison.OrdinalIgnoreCase); - - if (isDevelopment) - { - configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly()); - } - - var configuration = configurationBuilder.Build(); - - var services = new ServiceCollection(); - services.AddSingleton(configuration); - services.AddLogging(); - - services.AddMediatR(typeof(Program).Assembly); - + public void LoadAggregateWithoutSnapshot() + { + LoadAggregate(); + } + + //[Benchmark] + public void LoadAggregateWithSnapshot() + { + LoadAggregate(); + } + + [Benchmark] + public void LoadAndSaveAggregateWithSnapshot() + { + var aggregate = LoadAggregate(); + SaveAggregate(aggregate); + } + + [Benchmark] + public void LoadAndSaveAggregateWithoutSnapshot() + { + var aggregate = LoadAggregate(); + SaveAggregate(aggregate); + } + + //[Benchmark] + public void SaveAggregateWithSnapshot() + { + SaveAggregate((TestSnapshotAggregate)_loadedAggregate); + } + + //[Benchmark] + public void SaveAggregateWithoutSnapshot() + { + SaveAggregate(_loadedAggregate); + } + + public TAggregateRoot LoadAggregate() where TAggregateRoot : TestAggregate + { + using var scope = _container.CreateScope(); + var repository = scope.ServiceProvider.GetService>(); + var aggregate = repository.GetByIdAsync(_loadTestAggregateId, default).GetAwaiter().GetResult(); + + if (aggregate?.AggregateId == default(Guid)) + aggregate.AggregateId = _loadTestAggregateId; + + return aggregate; + } + + public void TryLoadRandomAggregate() where TAggregateRoot : TestAggregate + { + using var scope = _container.CreateScope(); + var repository = scope.ServiceProvider.GetService>(); + var aggregate = repository.GetByIdAsync(Guid.NewGuid(), default).GetAwaiter().GetResult(); + } + + public void SaveAggregate(TAggregateRoot aggregate) where TAggregateRoot : TestAggregate, new() + { + using var scope = _container.CreateScope(); + var repository = scope.ServiceProvider.GetService>(); + aggregate.DoAction($"Event {Guid.NewGuid()}"); + aggregate.DoAction($"Event {Guid.NewGuid()}"); + repository.SaveAsync(aggregate).GetAwaiter().GetResult(); + _loadedAggregate = aggregate; + } + + private void SeedEventRepository(bool useJunkData = false) where TAggregateRoot : TestAggregate, new() + { + if (useJunkData) + { + SeedJunkData(); + } + + SeedAggregates(NumberOfEvents, _loadTestAggregateId); + } + + private void SeedJunkData() where TAggregateRoot : TestAggregate, new() + { + var aggregateIds = Enumerable.Range(0, _junkDataAggregates).Select(x => Guid.NewGuid()).ToArray(); + + SeedAggregates(_junkDataEventsPerAggregate, aggregateIds); + } + + private void SeedAggregates(int eventNo, params Guid[] aggregateIds) where TAggregateRoot : TestAggregate, new() + { + using var scope = _container.CreateScope(); + var repository = scope.ServiceProvider.GetService>(); + + foreach (var aggregateId in aggregateIds) + { + var aggregate = new TAggregateRoot() { AggregateId = aggregateId }; + for (int i = 0; i < eventNo; i++) + { + aggregate.DoAction($"Value {i + 1}"); + + if ((i + 1) % _snapshotFrequency == 0) + repository.SaveAsync(aggregate).GetAwaiter().GetResult(); + } + + repository.SaveAsync(aggregate).GetAwaiter().GetResult(); + + aggregate.DoAction($"AdditionlValue 1"); + aggregate.DoAction($"AdditionlValue 2"); + aggregate.DoAction($"AdditionlValue 3"); + + repository.SaveAsync(aggregate).GetAwaiter().GetResult(); + + if (aggregateId == _loadTestAggregateId) + _loadedAggregate = aggregate; + } + } + + private static void MigrateNBBEventStore() + { + new AdoNetEventStoreDatabaseMigrator().ReCreateDatabaseObjects(default).Wait(); + } + + private static TestEvent GetATestEvent() + { + return new TestEvent("Lorem ipsum"); + } + + private static IServiceProvider BuildServiceProvider(Action addEventStoreAction) + { + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + + var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); + var isDevelopment = string.Equals(environment, "development", StringComparison.OrdinalIgnoreCase); + + if (isDevelopment) + { + configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly()); + } + + var configuration = configurationBuilder.Build(); + + var services = new ServiceCollection(); + services.AddSingleton(configuration); + services.AddLogging(); + + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); + services.AddEventStore(es => { es.UseNewtownsoftJson(); es.UseAdoNetEventRepository(opts => opts.FromConfiguration()); - }); - - addEventStoreAction(services); - - var container = services.BuildServiceProvider(); - return container; - } - - public record TestEvent(string Prop); - - public class TestAggregate : EventSourcedAggregateRoot + }); + + addEventStoreAction(services); + + var container = services.BuildServiceProvider(); + return container; + } + + public record TestEvent(string Prop); + + public class TestAggregate : EventSourcedAggregateRoot { - public Guid AggregateId { get; set; } - + public Guid AggregateId { get; set; } + protected List State { get; set; } = new List(); - public string Prop1 { get; protected set; } - - public override Guid GetIdentityValue() - { - return AggregateId; - } - - public void DoAction(string prop) - { - Emit(new TestEvent(prop)); - } - - private void Apply(TestEvent testEvent) - { - if (State.Count > 100) - State.Clear(); - - State.Add(testEvent.Prop); - } - } - - public class TestSnapshotAggregate : TestAggregate, IMementoProvider - { - public void SetMemento(TestSnapshot memento) - { - AggregateId = memento.AggregateId; - State = memento.State.ToList(); - } - - public TestSnapshot CreateMemento() - { - return new TestSnapshot(AggregateId, State.ToList()); - } - - void IMementoProvider.SetMemento(object memento) => SetMemento((TestSnapshot)memento); - object IMementoProvider.CreateMemento() => CreateMemento(); + public string Prop1 { get; protected set; } + + public override Guid GetIdentityValue() + { + return AggregateId; + } + + public void DoAction(string prop) + { + Emit(new TestEvent(prop)); + } + + private void Apply(TestEvent testEvent) + { + if (State.Count > 100) + State.Clear(); + + State.Add(testEvent.Prop); + } + } + + public class TestSnapshotAggregate : TestAggregate, IMementoProvider + { + public void SetMemento(TestSnapshot memento) + { + AggregateId = memento.AggregateId; + State = memento.State.ToList(); + } + + public TestSnapshot CreateMemento() + { + return new TestSnapshot(AggregateId, State.ToList()); + } + + void IMementoProvider.SetMemento(object memento) => SetMemento((TestSnapshot)memento); + object IMementoProvider.CreateMemento() => CreateMemento(); } - public class TestSnapshot - { - public Guid AggregateId { get; } - public IEnumerable State { get; } - - public TestSnapshot(Guid aggregateId, IEnumerable state) - { - AggregateId = aggregateId; - State = state; - } - } - } -} + public class TestSnapshot + { + public Guid AggregateId { get; } + public IEnumerable State { get; } + + public TestSnapshot(Guid aggregateId, IEnumerable state) + { + AggregateId = aggregateId; + State = state; + } + } + } +} diff --git a/test/Benchmarks/EventStoreBenchmarks/EventStoreBenchmarks.csproj b/test/Benchmarks/EventStoreBenchmarks/EventStoreBenchmarks.csproj index 69048d39..9d1fec9c 100644 --- a/test/Benchmarks/EventStoreBenchmarks/EventStoreBenchmarks.csproj +++ b/test/Benchmarks/EventStoreBenchmarks/EventStoreBenchmarks.csproj @@ -34,7 +34,7 @@ - + diff --git a/test/Integration/NBB.EventStore.IntegrationTests/SnapshotStoreDBIntegrationTests.cs b/test/Integration/NBB.EventStore.IntegrationTests/SnapshotStoreDBIntegrationTests.cs index e318f4c2..e243bb61 100644 --- a/test/Integration/NBB.EventStore.IntegrationTests/SnapshotStoreDBIntegrationTests.cs +++ b/test/Integration/NBB.EventStore.IntegrationTests/SnapshotStoreDBIntegrationTests.cs @@ -1,177 +1,177 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using FluentAssertions; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using NBB.Core.Abstractions; -using NBB.EventStore.Abstractions; -using NBB.EventStore.AdoNet.Migrations; -using NBB.MultiTenancy.Abstractions; -using NBB.MultiTenancy.Abstractions.Context; -using System; -using System.IO; +using FluentAssertions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using NBB.Core.Abstractions; +using NBB.EventStore.Abstractions; +using NBB.EventStore.AdoNet.Migrations; +using NBB.MultiTenancy.Abstractions; +using NBB.MultiTenancy.Abstractions.Context; +using System; +using System.IO; using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace NBB.EventStore.IntegrationTests -{ - [Collection("EventStoreDB")] - public class SnapshotStoreDbIntegrationTests : IClassFixture - { - [Fact] - public void Should_store_snapshot_thread_safe() - { - // Arrange - PrepareDb(); - var container = BuildAdoRepoServiceProvider(); - var stream = Guid.NewGuid().ToString(); - const int streamVersion = 0; - const int threadCount = 10; - var concurrencyExceptionCount = 0; - - using var scope = container.CreateScope(); - var snapshotStore = scope.ServiceProvider.GetService(); - - // Act - Parallel.For(0, threadCount, _ => - { - try - { - snapshotStore.StoreSnapshotAsync( - new SnapshotEnvelope( - new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }, streamVersion, stream), - CancellationToken.None - ).GetAwaiter().GetResult(); - } - catch (ConcurrencyUnrecoverableException) - { - Interlocked.Increment(ref concurrencyExceptionCount); - } - }); - var snapshot = snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None).Result; - - // Assert - snapshot.Should().NotBeNull(); - concurrencyExceptionCount.Should().Be(threadCount - 1); - } - - [Fact] - public void Should_retrieve_snapshot_with_latest_version() - { - // Arrange - PrepareDb(); - var container = BuildAdoRepoServiceProvider(); - var stream = Guid.NewGuid().ToString(); - const int threadCount = 10; - - using var scope = container.CreateScope(); - var snapshotStore = scope.ServiceProvider.GetService(); - - // Act - Parallel.For(0, threadCount, index => - { - snapshotStore.StoreSnapshotAsync( - new SnapshotEnvelope( - new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }, index, stream), - CancellationToken.None - ).GetAwaiter().GetResult(); - - }); - var snapshot = snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None).Result; - - // Assert - snapshot.Should().NotBeNull(); - snapshot.AggregateVersion.Should().Be(threadCount - 1); - } - - [Fact] - public async Task Should_load_stored_snapshot() - { - //Arrange - PrepareDb(); - var container = BuildAdoRepoServiceProvider(); - var stream = Guid.NewGuid().ToString(); - var snapshot = new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }; - var snapshotEnvelope = new SnapshotEnvelope(snapshot, 1, stream); - - using var scope = container.CreateScope(); - //Act - var snapshotStore = scope.ServiceProvider.GetService(); - - await snapshotStore.StoreSnapshotAsync(snapshotEnvelope, CancellationToken.None); - - var loadedSnapshotEnvelope = await snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None); - - //Assert - loadedSnapshotEnvelope.Should().NotBeNull(); - loadedSnapshotEnvelope.Should().BeEquivalentTo(snapshotEnvelope); +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace NBB.EventStore.IntegrationTests +{ + [Collection("EventStoreDB")] + public class SnapshotStoreDbIntegrationTests : IClassFixture + { + [Fact] + public void Should_store_snapshot_thread_safe() + { + // Arrange + PrepareDb(); + var container = BuildAdoRepoServiceProvider(); + var stream = Guid.NewGuid().ToString(); + const int streamVersion = 0; + const int threadCount = 10; + var concurrencyExceptionCount = 0; + + using var scope = container.CreateScope(); + var snapshotStore = scope.ServiceProvider.GetService(); + + // Act + Parallel.For(0, threadCount, _ => + { + try + { + snapshotStore.StoreSnapshotAsync( + new SnapshotEnvelope( + new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }, streamVersion, stream), + CancellationToken.None + ).GetAwaiter().GetResult(); + } + catch (ConcurrencyUnrecoverableException) + { + Interlocked.Increment(ref concurrencyExceptionCount); + } + }); + var snapshot = snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None).Result; + + // Assert + snapshot.Should().NotBeNull(); + concurrencyExceptionCount.Should().Be(threadCount - 1); + } + + [Fact] + public void Should_retrieve_snapshot_with_latest_version() + { + // Arrange + PrepareDb(); + var container = BuildAdoRepoServiceProvider(); + var stream = Guid.NewGuid().ToString(); + const int threadCount = 10; + + using var scope = container.CreateScope(); + var snapshotStore = scope.ServiceProvider.GetService(); + + // Act + Parallel.For(0, threadCount, index => + { + snapshotStore.StoreSnapshotAsync( + new SnapshotEnvelope( + new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }, index, stream), + CancellationToken.None + ).GetAwaiter().GetResult(); + + }); + var snapshot = snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None).Result; + + // Assert + snapshot.Should().NotBeNull(); + snapshot.AggregateVersion.Should().Be(threadCount - 1); + } + + [Fact] + public async Task Should_load_stored_snapshot() + { + //Arrange + PrepareDb(); + var container = BuildAdoRepoServiceProvider(); + var stream = Guid.NewGuid().ToString(); + var snapshot = new TestSnapshot { Prop1 = "aaa", Prop2 = "bbb" }; + var snapshotEnvelope = new SnapshotEnvelope(snapshot, 1, stream); + + using var scope = container.CreateScope(); + //Act + var snapshotStore = scope.ServiceProvider.GetService(); + + await snapshotStore.StoreSnapshotAsync(snapshotEnvelope, CancellationToken.None); + + var loadedSnapshotEnvelope = await snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None); + + //Assert + loadedSnapshotEnvelope.Should().NotBeNull(); + loadedSnapshotEnvelope.Should().BeEquivalentTo(snapshotEnvelope); } - [Fact] - public async Task Should_return_null_for_not_found_snapshot() - { - //Arrange - PrepareDb(); - var container = BuildAdoRepoServiceProvider(); - var stream = Guid.NewGuid().ToString(); - - using var scope = container.CreateScope(); - //Act - var snapshotStore = scope.ServiceProvider.GetService(); - var loadedSnapshotEnvelope = await snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None); - - //Assert - loadedSnapshotEnvelope.Should().BeNull(); - } - - private static IServiceProvider BuildAdoRepoServiceProvider() - { - var configurationBuilder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - - var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); - var isDevelopment = string.Equals(environment, "development", StringComparison.OrdinalIgnoreCase); - - if (isDevelopment) - { - configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly()); - } - - var configuration = configurationBuilder.Build(); - - - var services = new ServiceCollection(); - services.AddSingleton(configuration); - services.AddLogging(); - + [Fact] + public async Task Should_return_null_for_not_found_snapshot() + { + //Arrange + PrepareDb(); + var container = BuildAdoRepoServiceProvider(); + var stream = Guid.NewGuid().ToString(); + + using var scope = container.CreateScope(); + //Act + var snapshotStore = scope.ServiceProvider.GetService(); + var loadedSnapshotEnvelope = await snapshotStore.LoadSnapshotAsync(stream, CancellationToken.None); + + //Assert + loadedSnapshotEnvelope.Should().BeNull(); + } + + private static IServiceProvider BuildAdoRepoServiceProvider() + { + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + + var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"); + var isDevelopment = string.Equals(environment, "development", StringComparison.OrdinalIgnoreCase); + + if (isDevelopment) + { + configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly()); + } + + var configuration = configurationBuilder.Build(); + + + var services = new ServiceCollection(); + services.AddSingleton(configuration); + services.AddLogging(); + services.AddEventStore(es => { es.UseNewtownsoftJson(); es.UseMultiTenantAdoNetEventRepository(opts => opts.FromConfiguration()); - }); - - services.AddMultitenancy(configuration) - .AddSingleton(Mock.Of(x => + }); + + services.AddMultitenancy(configuration) + .AddSingleton(Mock.Of(x => x.TenantContext == new TenantContext(new Tenant(Guid.NewGuid(), null, true)))); - - var container = services.BuildServiceProvider(); - return container; - } - - private static void PrepareDb() - { - new AdoNetEventStoreDatabaseMigrator(isTestHost: true).ReCreateDatabaseObjects(null).Wait(); - } - } - - public class TestSnapshot - { - public string Prop1 { get; set; } + + var container = services.BuildServiceProvider(); + return container; + } + + private static void PrepareDb() + { + new AdoNetEventStoreDatabaseMigrator(isTestHost: true).ReCreateDatabaseObjects(null).Wait(); + } + } + + public class TestSnapshot + { + public string Prop1 { get; set; } public string Prop2 { get; set; } - } -} + } +} diff --git a/test/UnitTests/Data/NBB.Data.EventSourcing.Tests/EventSourcedRepositoryTests.cs b/test/UnitTests/Data/NBB.Data.EventSourcing.Tests/EventSourcedRepositoryTests.cs index cf4c7fd0..db3fbcd5 100644 --- a/test/UnitTests/Data/NBB.Data.EventSourcing.Tests/EventSourcedRepositoryTests.cs +++ b/test/UnitTests/Data/NBB.Data.EventSourcing.Tests/EventSourcedRepositoryTests.cs @@ -1,90 +1,90 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using FluentAssertions; -using MediatR; -using Microsoft.Extensions.Logging; -using Moq; -using NBB.Core.Abstractions; -using NBB.Data.EventSourcing.Infrastructure; -using NBB.Domain.Abstractions; -using NBB.EventStore.Abstractions; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace NBB.Data.EventSourcing.Tests -{ - public class EventSourcedRepositoryTests - { - public class TestEventSourcedAggregateRoot : IEventSourcedAggregateRoot, ISnapshotableEntity - { - public TestEventSourcedAggregateRoot() - { - - } - - public TestEventSourcedAggregateRoot(Guid id, int version, List domainEvents) - { - Id = id; - Version = version; - _domainEvents = domainEvents; - - } - - public int Version { get; set; } - - private readonly List _domainEvents; - +using FluentAssertions; +using MediatR; +using Microsoft.Extensions.Logging; +using Moq; +using NBB.Core.Abstractions; +using NBB.Data.EventSourcing.Infrastructure; +using NBB.Domain.Abstractions; +using NBB.EventStore.Abstractions; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace NBB.Data.EventSourcing.Tests +{ + public class EventSourcedRepositoryTests + { + public class TestEventSourcedAggregateRoot : IEventSourcedAggregateRoot, ISnapshotableEntity + { + public TestEventSourcedAggregateRoot() + { + + } + + public TestEventSourcedAggregateRoot(Guid id, int version, List domainEvents) + { + Id = id; + Version = version; + _domainEvents = domainEvents; + + } + + public int Version { get; set; } + + private readonly List _domainEvents; + public Guid Id { get; } public int SnapshotVersion { get; protected set; } public virtual int? SnapshotVersionFrequency => null; - public virtual IEnumerable GetUncommittedChanges() => _domainEvents; - - public void LoadFromHistory(IEnumerable history) - { - //throw new NotImplementedException(); - } - - public virtual void MarkChangesAsCommitted() - { - } - - public Guid GetIdentityValue() => Id; - object IIdentifiedEntity.GetIdentityValue() => this.GetIdentityValue(); - - public string GetTypeId() - { - return "asa"; + public virtual IEnumerable GetUncommittedChanges() => _domainEvents; + + public void LoadFromHistory(IEnumerable history) + { + //throw new NotImplementedException(); + } + + public virtual void MarkChangesAsCommitted() + { + } + + public Guid GetIdentityValue() => Id; + object IIdentifiedEntity.GetIdentityValue() => this.GetIdentityValue(); + + public string GetTypeId() + { + return "asa"; } - public (object snapshot, int snapshotVersion) TakeSnapshot() - { - return (null, Version); + public (object snapshot, int snapshotVersion) TakeSnapshot() + { + return (null, Version); } public void ApplySnapshot(object snapshot, int snapshotVersion) { } - } - - public class TestSnapshotAggregateRoot : TestEventSourcedAggregateRoot, IMementoProvider - { - public TestSnapshotAggregateRoot() - { - } - - public TestSnapshotAggregateRoot(Guid id, int version, int snapshotVersion, int? snapshotVersionFrequency, List domainEvents) - : base(id, version, domainEvents) - { - SnapshotVersion = snapshotVersion; - SnapshotVersionFrequency = snapshotVersionFrequency; + } + + public class TestSnapshotAggregateRoot : TestEventSourcedAggregateRoot, IMementoProvider + { + public TestSnapshotAggregateRoot() + { + } + + public TestSnapshotAggregateRoot(Guid id, int version, int snapshotVersion, int? snapshotVersionFrequency, List domainEvents) + : base(id, version, domainEvents) + { + SnapshotVersion = snapshotVersion; + SnapshotVersionFrequency = snapshotVersionFrequency; } @@ -93,206 +93,206 @@ public void SetMemento(object snapshot) { } - public object CreateMemento() - { - return null; - } - - public override int? SnapshotVersionFrequency { get; } - } - - [Fact] - public async Task Should_save_events_in_event_store_when_aggregate_is_saved() - { - //Arrange - //var eventStoreMock = new Mock(); - var eventStoreMock = new TestEventStore(); - var sut = new EventSourcedRepository(eventStoreMock, Mock.Of(), Mock.Of(), new EventSourcingOptions(), Mock.Of>>()); - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestEventSourcedAggregateRoot(Guid.NewGuid(), 5, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - //eventStoreMock.Verify(es => es.AppendEventsToStreamAsync(It.IsAny(), It.Is>(de=> de.Single() == domainEvent), null, It.IsAny())); - eventStoreMock.AppendEventsToStreamAsyncCallsCount.Should().Be(1); - } - - [Fact] - public async Task Should_save_snapshot_in_snapshot_store_when_aggregate_is_saved() - { - //Arrange - var snapshotStore = Mock.Of(); - var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), new EventSourcingOptions { DefaultSnapshotVersionFrequency = 1 }, Mock.Of>>()); - - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 1000, 1, 10, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - Mock.Get(snapshotStore) - .Verify( - x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), - Times.Once); - } - - [Fact] - public async Task Should_not_take_snapshot_below_default_frequency() - { - //Arrange - var snapshotStore = Mock.Of(); - var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 2}; - var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); - - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 2, 1, null, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - Mock.Get(snapshotStore) - .Verify( - x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), - Times.Never); - } - - [Fact] - public async Task Should_take_snapshot_at_default_frequency() - { - //Arrange - var snapshotStore = Mock.Of(); - var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 2}; - var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); - - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 3, 1, null, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - Mock.Get(snapshotStore) - .Verify( - x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), - Times.Once); - } - - [Fact] - public async Task Should_not_take_snapshot_below_custom_frequency() - { - //Arrange - var snapshotStore = Mock.Of(); - var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 10}; - var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); - - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 2, 1, 2, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - Mock.Get(snapshotStore) - .Verify( - x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), - Times.Never); - } - - [Fact] - public async Task Should_take_snapshot_at_custom_frequency() - { - //Arrange - var snapshotStore = Mock.Of(); - var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 10}; - var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); - - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 3, 1, 2, domainEvents); - - //Act - await sut.SaveAsync(testAggregate, CancellationToken.None); - - //Assert - Mock.Get(snapshotStore) - .Verify( - x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), - Times.Once); - } - - [Fact] - public async Task Should_mark_changes_as_committed_for_aggregate_when_aggregate_is_saved() - { - //Arrange - var eventStoreMock = new Mock(); - var sut = new EventSourcedRepository(eventStoreMock.Object, Mock.Of(), Mock.Of(), new EventSourcingOptions(), Mock.Of>>()); - var domainEvent = Mock.Of(); - var domainEvents = new List { domainEvent }; - var testAggregate = new Mock(); - testAggregate.Setup(a => a.GetUncommittedChanges()).Returns(domainEvents); - - //Act - await sut.SaveAsync(testAggregate.Object, CancellationToken.None); - - //Assert - testAggregate.Verify(a => a.MarkChangesAsCommitted(), Times.Once); - } - - [Fact] - public async Task Should_dispatch_events() - { - //Arrange - var eventStoreMock = new Mock(); - //var wasCalled = false; - //var mediatorMock = new Mock(); - //mediatorMock - // .Setup(m => m.Publish(It.IsAny(), It.IsAny())) - // .Callback(() => - // { - // wasCalled = true; - // }); - // .Returns(Task.CompletedTask); - - //.ReturnsAsync(Task.CompletedTask); //<-- return Task to allow await to continue - //mediatorMock.Setup(x=> x.Publish()) - var mediatorMock = new TestMediator(); - - var sut = new EventSourcedRepository(eventStoreMock.Object, Mock.Of(), mediatorMock, new EventSourcingOptions(), Mock.Of>>()); - var testAggregate = new Mock(); - var domainEvent = new TestDomainEvent(); - var domainEvents = new List { domainEvent }; - testAggregate.Setup(a => a.GetUncommittedChanges()).Returns(domainEvents); - //Act - await sut.SaveAsync(testAggregate.Object, CancellationToken.None); - - //Assert - //mediatorMock.Verify(m => m.Publish(domainEvent, It.IsAny()), Times.Once()); - - mediatorMock.PublishCallsCount.Should().Be(1); - - } - } - - public class TestDomainEvent : object, INotification - { - public DateTime CreationDate => DateTime.Now; - - public Guid EventId => Guid.Empty; - - public int SequenceNumber { get; set; } - } - - public class TestMediator : IMediator - { + public object CreateMemento() + { + return null; + } + + public override int? SnapshotVersionFrequency { get; } + } + + [Fact] + public async Task Should_save_events_in_event_store_when_aggregate_is_saved() + { + //Arrange + //var eventStoreMock = new Mock(); + var eventStoreMock = new TestEventStore(); + var sut = new EventSourcedRepository(eventStoreMock, Mock.Of(), Mock.Of(), new EventSourcingOptions(), Mock.Of>>()); + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestEventSourcedAggregateRoot(Guid.NewGuid(), 5, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + //eventStoreMock.Verify(es => es.AppendEventsToStreamAsync(It.IsAny(), It.Is>(de=> de.Single() == domainEvent), null, It.IsAny())); + eventStoreMock.AppendEventsToStreamAsyncCallsCount.Should().Be(1); + } + + [Fact] + public async Task Should_save_snapshot_in_snapshot_store_when_aggregate_is_saved() + { + //Arrange + var snapshotStore = Mock.Of(); + var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), new EventSourcingOptions { DefaultSnapshotVersionFrequency = 1 }, Mock.Of>>()); + + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 1000, 1, 10, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + Mock.Get(snapshotStore) + .Verify( + x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), + Times.Once); + } + + [Fact] + public async Task Should_not_take_snapshot_below_default_frequency() + { + //Arrange + var snapshotStore = Mock.Of(); + var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 2}; + var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); + + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 2, 1, null, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + Mock.Get(snapshotStore) + .Verify( + x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), + Times.Never); + } + + [Fact] + public async Task Should_take_snapshot_at_default_frequency() + { + //Arrange + var snapshotStore = Mock.Of(); + var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 2}; + var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); + + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 3, 1, null, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + Mock.Get(snapshotStore) + .Verify( + x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), + Times.Once); + } + + [Fact] + public async Task Should_not_take_snapshot_below_custom_frequency() + { + //Arrange + var snapshotStore = Mock.Of(); + var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 10}; + var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); + + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 2, 1, 2, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + Mock.Get(snapshotStore) + .Verify( + x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), + Times.Never); + } + + [Fact] + public async Task Should_take_snapshot_at_custom_frequency() + { + //Arrange + var snapshotStore = Mock.Of(); + var options = new EventSourcingOptions {DefaultSnapshotVersionFrequency = 10}; + var sut = new EventSourcedRepository(Mock.Of(), snapshotStore, Mock.Of(), options, Mock.Of>>()); + + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new TestSnapshotAggregateRoot(Guid.NewGuid(), 3, 1, 2, domainEvents); + + //Act + await sut.SaveAsync(testAggregate, CancellationToken.None); + + //Assert + Mock.Get(snapshotStore) + .Verify( + x => x.StoreSnapshotAsync(It.IsAny(), It.IsAny()), + Times.Once); + } + + [Fact] + public async Task Should_mark_changes_as_committed_for_aggregate_when_aggregate_is_saved() + { + //Arrange + var eventStoreMock = new Mock(); + var sut = new EventSourcedRepository(eventStoreMock.Object, Mock.Of(), Mock.Of(), new EventSourcingOptions(), Mock.Of>>()); + var domainEvent = Mock.Of(); + var domainEvents = new List { domainEvent }; + var testAggregate = new Mock(); + testAggregate.Setup(a => a.GetUncommittedChanges()).Returns(domainEvents); + + //Act + await sut.SaveAsync(testAggregate.Object, CancellationToken.None); + + //Assert + testAggregate.Verify(a => a.MarkChangesAsCommitted(), Times.Once); + } + + [Fact] + public async Task Should_dispatch_events() + { + //Arrange + var eventStoreMock = new Mock(); + //var wasCalled = false; + //var mediatorMock = new Mock(); + //mediatorMock + // .Setup(m => m.Publish(It.IsAny(), It.IsAny())) + // .Callback(() => + // { + // wasCalled = true; + // }); + // .Returns(Task.CompletedTask); + + //.ReturnsAsync(Task.CompletedTask); //<-- return Task to allow await to continue + //mediatorMock.Setup(x=> x.Publish()) + var mediatorMock = new TestMediator(); + + var sut = new EventSourcedRepository(eventStoreMock.Object, Mock.Of(), mediatorMock, new EventSourcingOptions(), Mock.Of>>()); + var testAggregate = new Mock(); + var domainEvent = new TestDomainEvent(); + var domainEvents = new List { domainEvent }; + testAggregate.Setup(a => a.GetUncommittedChanges()).Returns(domainEvents); + //Act + await sut.SaveAsync(testAggregate.Object, CancellationToken.None); + + //Assert + //mediatorMock.Verify(m => m.Publish(domainEvent, It.IsAny()), Times.Once()); + + mediatorMock.PublishCallsCount.Should().Be(1); + + } + } + + public class TestDomainEvent : object, INotification + { + public DateTime CreationDate => DateTime.Now; + + public Guid EventId => Guid.Empty; + + public int SequenceNumber { get; set; } + } + + public class TestMediator : IMediator + { public int PublishCallsCount { get; private set; } public IAsyncEnumerable CreateStream(IStreamRequest request, CancellationToken cancellationToken = default) @@ -307,13 +307,13 @@ public IAsyncEnumerable CreateStream(object request, CancellationToken c public Task Publish(object notification, CancellationToken cancellationToken = default) { - this.PublishCallsCount++; + this.PublishCallsCount++; return Task.CompletedTask; } public Task Publish(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification { - this.PublishCallsCount++; + this.PublishCallsCount++; return Task.CompletedTask; } @@ -326,21 +326,26 @@ public Task Send(object request, CancellationToken cancellationToken = d { throw new NotImplementedException(); } - } - - public class TestEventStore : IEventStore - { - public int AppendEventsToStreamAsyncCallsCount { get; private set; } - - public Task AppendEventsToStreamAsync(string stream, IEnumerable events, int? expectedVersion, CancellationToken cancellationToken = default) - { - AppendEventsToStreamAsyncCallsCount++; - return Task.CompletedTask; - } - + + public Task Send(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest + { + throw new NotImplementedException(); + } + } + + public class TestEventStore : IEventStore + { + public int AppendEventsToStreamAsyncCallsCount { get; private set; } + + public Task AppendEventsToStreamAsync(string stream, IEnumerable events, int? expectedVersion, CancellationToken cancellationToken = default) + { + AppendEventsToStreamAsyncCallsCount++; + return Task.CompletedTask; + } + public Task> GetEventsFromStreamAsync(string stream, int? startFromVersion, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - } -} + } +} diff --git a/test/UnitTests/Messaging/NBB.Messaging.Host.Tests/MessagingHostBuilderTests.cs b/test/UnitTests/Messaging/NBB.Messaging.Host.Tests/MessagingHostBuilderTests.cs index c3c3e9bf..7ea4c800 100644 --- a/test/UnitTests/Messaging/NBB.Messaging.Host.Tests/MessagingHostBuilderTests.cs +++ b/test/UnitTests/Messaging/NBB.Messaging.Host.Tests/MessagingHostBuilderTests.cs @@ -50,7 +50,7 @@ public void Should_register_handled_commands_singleton() Mock.Get(services).Setup(x => x.GetEnumerator()) .Returns(new List { - new ServiceDescriptor(typeof(IRequestHandler), new CommandHandler()) + new ServiceDescriptor(typeof(IRequestHandler), new CommandHandler()) }.GetEnumerator()); //Act @@ -218,7 +218,7 @@ public class MessageToScan : MessageToScanBase public class CommandHandler : IRequestHandler { - public Task Handle(CommandMessage request, CancellationToken cancellationToken) + public Task Handle(CommandMessage request, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Identification.Tests/Extensions/TenantTokenResolverConfigurationTests.cs b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Identification.Tests/Extensions/TenantTokenResolverConfigurationTests.cs index 48f8d337..f008858d 100644 --- a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Identification.Tests/Extensions/TenantTokenResolverConfigurationTests.cs +++ b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Identification.Tests/Extensions/TenantTokenResolverConfigurationTests.cs @@ -2,6 +2,8 @@ // This source code is licensed under the MIT license. using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; +using Moq; using NBB.MultiTenancy.Identification.Extensions; using NBB.MultiTenancy.Identification.Resolvers; using System; @@ -48,7 +50,7 @@ public void Adding_Resolver_Without_Params_Should_Create_Instance() _sut.AddTenantTokenResolver(); // Act - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); // Assert result.Should().NotBeNull(); @@ -66,7 +68,7 @@ public void Adding_Resolver_With_Params_Should_Create_Instance() _sut.AddTenantTokenResolver(parameter, parameter, parameter); // Act - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); var args = ((MockResolver)result.First()).Args; // Assert @@ -106,7 +108,7 @@ public void Adding_Resolver_Type_Without_Params_Should_Create_Instance() _sut.AddTenantTokenResolver(typeof(MockResolver)); // Act - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); // Assert result.Should().NotBeNull(); @@ -150,7 +152,7 @@ public void Adding_Resolver_Type_With_Params_Should_Create_Instance() _sut.AddTenantTokenResolver(typeof(MockResolver), parameter, parameter, parameter); // Act - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); var args = ((MockResolver)result.First()).Args; // Assert @@ -179,7 +181,7 @@ public void Adding_Resolver_Instance_Should_Create_Instance() // Act _sut.AddTenantTokenResolver(resolver); - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); // Assert result.Should().NotBeNull(); @@ -211,7 +213,7 @@ public void Adding_Implementation_Factory_Should_Create_Instance() // Act _sut.AddTenantTokenResolver(ImplementationFactory); - var result = _sut.GetTenantTokenResolvers(null).ToList(); + var result = _sut.GetTenantTokenResolvers(new ServiceCollection().BuildServiceProvider()).ToList(); // Assert result.Should().NotBeNull(); diff --git a/test/UnitTests/Projections/NBB.ProjectR.Tests/NBB.ProjectR.Tests.csproj b/test/UnitTests/Projections/NBB.ProjectR.Tests/NBB.ProjectR.Tests.csproj index 5e366a22..ac7346c0 100644 --- a/test/UnitTests/Projections/NBB.ProjectR.Tests/NBB.ProjectR.Tests.csproj +++ b/test/UnitTests/Projections/NBB.ProjectR.Tests/NBB.ProjectR.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/UnitTests/Projections/NBB.ProjectR.Tests/TestFixture.cs b/test/UnitTests/Projections/NBB.ProjectR.Tests/TestFixture.cs index 4ef73395..fd37bf84 100644 --- a/test/UnitTests/Projections/NBB.ProjectR.Tests/TestFixture.cs +++ b/test/UnitTests/Projections/NBB.ProjectR.Tests/TestFixture.cs @@ -1,30 +1,30 @@ // Copyright (c) TotalSoft. // This source code is licensed under the MIT license. -using MediatR; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace NBB.ProjectR.Tests -{ - public class TestFixture - { - public ServiceProvider BuildServiceProvider() - { - var services = new ServiceCollection(); - services.AddProjectR(GetType().Assembly); - services.AddMediatR(GetType().Assembly); - services - .AddEffects() - .AddMessagingEffects() - .AddMediatorEffects(); - services.AddMessageBus().AddInProcessTransport(); - services.AddEventStore(b => b.UseNewtownsoftJson().UseInMemoryEventRepository()); - services.AddLogging(); - services.AddSingleton(new ConfigurationBuilder().Build()); - - return services.BuildServiceProvider(); - - } - } -} +using MediatR; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace NBB.ProjectR.Tests +{ + public class TestFixture + { + public ServiceProvider BuildServiceProvider() + { + var services = new ServiceCollection(); + services.AddProjectR(GetType().Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(GetType().Assembly)); + services + .AddEffects() + .AddMessagingEffects() + .AddMediatorEffects(); + services.AddMessageBus().AddInProcessTransport(); + services.AddEventStore(b => b.UseNewtownsoftJson().UseInMemoryEventRepository()); + services.AddLogging(); + services.AddSingleton(new ConfigurationBuilder().Build()); + + return services.BuildServiceProvider(); + + } + } +}