diff --git a/Application/Pages/Index.cshtml.cs b/Application/Pages/Index.cshtml.cs
index 806a114..f798ee6 100644
--- a/Application/Pages/Index.cshtml.cs
+++ b/Application/Pages/Index.cshtml.cs
@@ -1,4 +1,3 @@
-using Akka.Actor;
using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
diff --git a/Application/PlanTempus.Application.csproj b/Application/PlanTempus.Application.csproj
index 17391d4..b0826ac 100644
--- a/Application/PlanTempus.Application.csproj
+++ b/Application/PlanTempus.Application.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
diff --git a/Core/CommandQueries/Command.cs b/Core/CommandQueries/Command.cs
new file mode 100644
index 0000000..ed8da3b
--- /dev/null
+++ b/Core/CommandQueries/Command.cs
@@ -0,0 +1,7 @@
+namespace PlanTempus.Core.CommandQueries;
+
+public abstract class Command : ICommand
+{
+ public required Guid CorrelationId { get; set; }
+ public Guid TransactionId { get; set; }
+}
\ No newline at end of file
diff --git a/Core/CommandQueries/CommandResponse.cs b/Core/CommandQueries/CommandResponse.cs
new file mode 100644
index 0000000..1b0bac7
--- /dev/null
+++ b/Core/CommandQueries/CommandResponse.cs
@@ -0,0 +1,16 @@
+namespace PlanTempus.Core.CommandQueries;
+
+public class CommandResponse
+{
+ public Guid RequestId { get; }
+ public Guid CorrelationId { get; }
+ public Guid? TransactionId { get; }
+ public DateTime CreatedAt { get; }
+
+ public CommandResponse(Guid correlationId)
+ {
+ CorrelationId = correlationId;
+ RequestId = Guid.CreateVersion7();
+ CreatedAt = DateTime.Now;
+ }
+}
\ No newline at end of file
diff --git a/Core/CommandQueries/ICommand.cs b/Core/CommandQueries/ICommand.cs
new file mode 100644
index 0000000..cb5e2e1
--- /dev/null
+++ b/Core/CommandQueries/ICommand.cs
@@ -0,0 +1,7 @@
+namespace PlanTempus.Core.CommandQueries;
+
+public interface ICommand
+{
+ Guid CorrelationId { get; set; }
+ Guid TransactionId { get; set; }
+}
\ No newline at end of file
diff --git a/Core/Database/DatabaseScope.cs b/Core/Database/DatabaseScope.cs
index 40db7c4..2d5b5e5 100644
--- a/Core/Database/DatabaseScope.cs
+++ b/Core/Database/DatabaseScope.cs
@@ -15,6 +15,7 @@ public class DatabaseScope : IDisposable
Connection = connection;
_operation = operation;
_operation.Telemetry.Success = true;
+ _operation.Telemetry.Timestamp = DateTimeOffset.UtcNow;
_stopwatch = Stopwatch.StartNew();
}
diff --git a/Core/ModuleRegistry/TelemetryModule.cs b/Core/ModuleRegistry/TelemetryModule.cs
index cdef080..8b8e887 100644
--- a/Core/ModuleRegistry/TelemetryModule.cs
+++ b/Core/ModuleRegistry/TelemetryModule.cs
@@ -17,7 +17,7 @@ namespace PlanTempus.Core.ModuleRegistry
var client = new Microsoft.ApplicationInsights.TelemetryClient(configuration);
client.Context.GlobalProperties["Application"] = GetType().Namespace?.Split('.')[0];
client.Context.GlobalProperties["MachineName"] = Environment.MachineName;
- client.Context.GlobalProperties["Version"] = Environment.Version.ToString();
+ client.Context.GlobalProperties["CLRVersion"] = Environment.Version.ToString();
client.Context.GlobalProperties["ProcessorCount"] = Environment.ProcessorCount.ToString();
builder.Register(c => client).InstancePerLifetimeScope();
diff --git a/Core/PlanTempus.Core.csproj b/Core/PlanTempus.Core.csproj
index 7fc76f2..e35b32e 100644
--- a/Core/PlanTempus.Core.csproj
+++ b/Core/PlanTempus.Core.csproj
@@ -1,30 +1,28 @@
-
-
+
-
- net8.0
- enable
-
+
+ net9.0
+ enable
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/Database/PlanTempus.Database.csproj b/Database/PlanTempus.Database.csproj
index 50d49a6..76de5e5 100644
--- a/Database/PlanTempus.Database.csproj
+++ b/Database/PlanTempus.Database.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
diff --git a/PlanTempus.Components/CommandHandler.cs b/PlanTempus.Components/CommandHandler.cs
index 85248e1..93c55cb 100644
--- a/PlanTempus.Components/CommandHandler.cs
+++ b/PlanTempus.Components/CommandHandler.cs
@@ -1,13 +1,14 @@
using Autofac;
using PlanTempus.Components.Users.Create;
+using PlanTempus.Core.CommandQueries;
namespace PlanTempus.Components;
public class CommandHandler(IComponentContext context) : ICommandHandler
{
- public async Task Handle(TCommand command)
+ public async Task Handle(TCommand command) where TCommand : ICommand
{
- var handler = context.Resolve>();
+ var handler = context.Resolve>();
return await handler.Handle(command);
}
}
\ No newline at end of file
diff --git a/PlanTempus.Components/ICommandHandler.cs b/PlanTempus.Components/ICommandHandler.cs
index 6eb35d7..8aa970c 100644
--- a/PlanTempus.Components/ICommandHandler.cs
+++ b/PlanTempus.Components/ICommandHandler.cs
@@ -1,13 +1,15 @@
-namespace PlanTempus.Components;
+using PlanTempus.Core.CommandQueries;
+
+namespace PlanTempus.Components;
public interface ICommandHandler
{
- Task Handle(TCommand command);
+ Task Handle(TCommand command) where TCommand : ICommand;
}
-public interface ICommandHandler
+public interface ICommandHandler where TCommand : ICommand
{
- Task Handle(T input);
+ Task Handle(TCommand command);
}
public interface ICommandHandlerDecorator
diff --git a/PlanTempus.Components/ModuleRegistry/CommandModule.cs b/PlanTempus.Components/ModuleRegistry/CommandModule.cs
index 4f153ec..23a1579 100644
--- a/PlanTempus.Components/ModuleRegistry/CommandModule.cs
+++ b/PlanTempus.Components/ModuleRegistry/CommandModule.cs
@@ -1,5 +1,6 @@
using Autofac;
using PlanTempus.Components.Users.Create;
+using PlanTempus.Core.CommandQueries;
using PlanTempus.Core.SeqLogging;
namespace PlanTempus.Components.ModuleRegistry
@@ -10,35 +11,27 @@ namespace PlanTempus.Components.ModuleRegistry
protected override void Load(ContainerBuilder builder)
{
-
builder.RegisterType()
.As()
.InstancePerLifetimeScope();
-
- builder.RegisterAssemblyTypes(ThisAssembly)
- .Where(t => !typeof(ICommandHandlerDecorator).IsAssignableFrom(t))
- .AsClosedTypesOf(typeof(ICommandHandler<,>))
- .InstancePerLifetimeScope();
-
-
- // Registrer alle handlers
- // builder.RegisterAssemblyTypes(ThisAssembly)
- // .AsClosedTypesOf(typeof(ICommandHandler<,>))
- // .InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(ThisAssembly)
- .As();
-
-
- builder.RegisterDecorator(
- typeof(CreateUserHandlerDecorator),
- typeof(ICommandHandler));
+ .Where(t => !typeof(ICommandHandlerDecorator).IsAssignableFrom(t))
+ .AsClosedTypesOf(typeof(ICommandHandler<>))
+ .InstancePerLifetimeScope();
+
+ builder.RegisterAssemblyTypes(ThisAssembly)
+ .As();
+
+
+ builder.RegisterGenericDecorator(
+ typeof(CommandHandlerDecorator<>),
+ typeof(ICommandHandler<>));
//
// Registrer en decorator for alle ICommandHandler
// builder.RegisterGenericDecorator(
// typeof(CommandHandlerDecorator<,>),
// typeof(ICommandHandler<,>));
-
}
}
}
\ No newline at end of file
diff --git a/PlanTempus.Components/PlanTempus.Components.csproj b/PlanTempus.Components/PlanTempus.Components.csproj
index d925cd4..2ea9caa 100644
--- a/PlanTempus.Components/PlanTempus.Components.csproj
+++ b/PlanTempus.Components/PlanTempus.Components.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
diff --git a/PlanTempus.Components/Users/Create/CreateUserHandlerDecorator.cs b/PlanTempus.Components/Users/Create/CommandHandlerDecorator.cs
similarity index 56%
rename from PlanTempus.Components/Users/Create/CreateUserHandlerDecorator.cs
rename to PlanTempus.Components/Users/Create/CommandHandlerDecorator.cs
index 8f9289c..c2b7531 100644
--- a/PlanTempus.Components/Users/Create/CreateUserHandlerDecorator.cs
+++ b/PlanTempus.Components/Users/Create/CommandHandlerDecorator.cs
@@ -1,27 +1,30 @@
using System.Diagnostics;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
+using PlanTempus.Core.CommandQueries;
namespace PlanTempus.Components.Users.Create;
-public class CreateUserHandlerDecorator(
- ICommandHandler decoratedHandler,
- TelemetryClient telemetryClient)
- : ICommandHandler, ICommandHandlerDecorator
+public class CommandHandlerDecorator(
+ ICommandHandler decoratedHandler,
+ TelemetryClient telemetryClient) : ICommandHandler, ICommandHandlerDecorator where TCommand : ICommand
{
- public async Task Handle(CreateUserCommand command)
+ public async Task Handle(TCommand command)
{
// var correlationId = Activity.Current?.RootId ?? command.CorrelationId;
using (var operation =
- telemetryClient.StartOperation($"Handle {nameof(CreateUserCommand)}",
+ telemetryClient.StartOperation($"Handle {decoratedHandler.GetType().FullName}",
command.CorrelationId.ToString()))
{
try
{
operation.Telemetry.Properties["CorrelationId"] = command.CorrelationId.ToString();
+ operation.Telemetry.Properties["TransactionId"] = command.TransactionId.ToString();
+
var result = await decoratedHandler.Handle(command);
+ operation.Telemetry.Properties["RequestId"] = result.RequestId.ToString();
operation.Telemetry.Success = true;
return result;
@@ -32,7 +35,9 @@ public class CreateUserHandlerDecorator(
telemetryClient.TrackException(ex, new Dictionary
{
- ["CommandType"] = nameof(CreateUserCommand)
+ ["CorrelationId"] = command.CorrelationId.ToString(),
+ ["Command"] = command.GetType().Name,
+ ["CommandHandler"] = decoratedHandler.GetType().FullName
});
throw;
}
diff --git a/PlanTempus.Components/Users/Create/CreateUserCommand.cs b/PlanTempus.Components/Users/Create/CreateUserCommand.cs
index 7a69f53..5d0ef11 100644
--- a/PlanTempus.Components/Users/Create/CreateUserCommand.cs
+++ b/PlanTempus.Components/Users/Create/CreateUserCommand.cs
@@ -1,15 +1,11 @@
+using PlanTempus.Core.CommandQueries;
+
namespace PlanTempus.Components.Users.Create
{
- public interface ICommand
- {
- Guid CorrelationId { get; set; }
- }
-
- public class CreateUserCommand : ICommand
+ public class CreateUserCommand : Command
{
public required string Email { get; set; }
public required string Password { get; set; }
public bool IsActive { get; set; } = true;
- public required Guid CorrelationId { get; set; }
}
}
\ No newline at end of file
diff --git a/PlanTempus.Components/Users/Create/CreateUserController.cs b/PlanTempus.Components/Users/Create/CreateUserController.cs
index 7ed1e0f..487b0dc 100644
--- a/PlanTempus.Components/Users/Create/CreateUserController.cs
+++ b/PlanTempus.Components/Users/Create/CreateUserController.cs
@@ -1,34 +1,31 @@
using Microsoft.AspNetCore.Mvc;
+using PlanTempus.Core.CommandQueries;
namespace PlanTempus.Components.Users.Create
{
- [ApiController]
- [Route("api/users")]
- public class CreateUserController(CreateUserHandler handler, CreateUserValidator validator) : ControllerBase
- {
- [HttpPost]
- public async Task> Create([FromBody] CreateUserCommand command)
- {
- try
- {
- var validationResult = await validator.ValidateAsync(command);
- if (!validationResult.IsValid)
- {
- return BadRequest(validationResult.Errors);
- }
+ [ApiController]
+ [Route("api/users")]
+ public class CreateUserController(CreateUserHandler handler, CreateUserValidator validator) : ControllerBase
+ {
+ [HttpPost]
+ public async Task> Create([FromBody] CreateUserCommand command)
+ {
+ try
+ {
+ var validationResult = await validator.ValidateAsync(command);
+ if (!validationResult.IsValid)
+ {
+ return BadRequest(validationResult.Errors);
+ }
- var result = await handler.Handle(command);
-
- return CreatedAtAction(
- nameof(CreateUserCommand),
- "GetUser",
- new { id = result.Id },
- result);
- }
- catch (Exception ex)
- {
- return BadRequest(ex.Message);
- }
- }
- }
+ var result = await handler.Handle(command);
+
+ return Accepted($"/api/requests/{result.RequestId}", result);
+ }
+ catch (Exception ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/PlanTempus.Components/Users/Create/CreateUserHandler.cs b/PlanTempus.Components/Users/Create/CreateUserHandler.cs
index 39c63ff..651f899 100644
--- a/PlanTempus.Components/Users/Create/CreateUserHandler.cs
+++ b/PlanTempus.Components/Users/Create/CreateUserHandler.cs
@@ -3,17 +3,16 @@ using Microsoft.ApplicationInsights;
using Npgsql;
using PlanTempus.Components.Users.Exceptions;
using PlanTempus.Core;
+using PlanTempus.Core.CommandQueries;
using PlanTempus.Core.Database;
-using PlanTempus.Core.Telemetry;
namespace PlanTempus.Components.Users.Create
{
public class CreateUserHandler(
- TelemetryClient telemetryClient,
IDatabaseOperations databaseOperations,
- ISecureTokenizer secureTokenizer) : ICommandHandler
+ ISecureTokenizer secureTokenizer) : ICommandHandler
{
- public async Task Handle(CreateUserCommand command)
+ public async Task Handle(CreateUserCommand command)
{
using var db = databaseOperations.CreateScope(nameof(CreateUserHandler));
try
@@ -28,20 +27,19 @@ namespace PlanTempus.Components.Users.Create
var data = await db.Connection.QuerySqlAsync(sql, new
{
- Email = command.Email,
+ command.Email,
PasswordHash = secureTokenizer.TokenizeText(command.Password),
SecurityStamp = Guid.NewGuid().ToString("N"),
EmailConfirmed = false,
AccessFailedCount = 0,
LockoutEnabled = false,
- IsActive = command.IsActive,
+ command.IsActive,
});
var result = data.First();
-
- return result;
+ return new CommandResponse(command.CorrelationId);
}
catch (PostgresException ex) when (ex.SqlState == "23505")
{
diff --git a/PlanTempus.X.BDD/PlanTempus.X.BDD.csproj b/PlanTempus.X.BDD/PlanTempus.X.BDD.csproj
index 8844c36..0b2c521 100644
--- a/PlanTempus.X.BDD/PlanTempus.X.BDD.csproj
+++ b/PlanTempus.X.BDD/PlanTempus.X.BDD.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
false
diff --git a/SetupInfrastructure/PlanTempus.SetupInfrastructure.csproj b/SetupInfrastructure/PlanTempus.SetupInfrastructure.csproj
index a813b20..5c9236b 100644
--- a/SetupInfrastructure/PlanTempus.SetupInfrastructure.csproj
+++ b/SetupInfrastructure/PlanTempus.SetupInfrastructure.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net9.0
enable
diff --git a/Tests/CommandQueryHandlerTests/HandlerTest.cs b/Tests/CommandQueryHandlerTests/HandlerTest.cs
index 4d3c262..b1c4742 100644
--- a/Tests/CommandQueryHandlerTests/HandlerTest.cs
+++ b/Tests/CommandQueryHandlerTests/HandlerTest.cs
@@ -2,6 +2,7 @@ using Autofac;
using Insight.Database;
using PlanTempus.Components;
using PlanTempus.Components.Users.Create;
+using PlanTempus.Core.CommandQueries;
using PlanTempus.Core.Database;
using PlanTempus.Core.Database.ConnectionFactory;
using Shouldly;
@@ -24,13 +25,13 @@ public class HandlerTest : TestFixture
var command = new CreateUserCommand
{
- Email = "lloyd@dumbanddumber.com1", // Lloyd Christmas
+ Email = "lloyd@dumbanddumber.com3", // Lloyd Christmas
Password = "1234AceVentura#LOL", // Ace Ventura
IsActive = true,
CorrelationId = Guid.NewGuid()
};
- var result = await commandHandler.Handle(command);
+ var result = await commandHandler.Handle(command);
result.ShouldNotBeNull();
}
diff --git a/Tests/PlanTempus.X.TDD.csproj b/Tests/PlanTempus.X.TDD.csproj
index ec3d895..0e69882 100644
--- a/Tests/PlanTempus.X.TDD.csproj
+++ b/Tests/PlanTempus.X.TDD.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
enable
false