diff --git a/Hestia.Access/Hestia.Access.csproj b/Hestia.Access/Hestia.Access.csproj
index a6def66..d680542 100644
--- a/Hestia.Access/Hestia.Access.csproj
+++ b/Hestia.Access/Hestia.Access.csproj
@@ -6,12 +6,9 @@
enable
-
-
-
-
+
diff --git a/Hestia.Access/Requests/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommand.cs b/Hestia.Access/Requests/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommand.cs
index 104e27d..d21bfb3 100644
--- a/Hestia.Access/Requests/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommand.cs
+++ b/Hestia.Access/Requests/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommand.cs
@@ -1,4 +1,5 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Types;
namespace Hestia.Access.Requests.Authentication.Commands.CreateTokenLog;
diff --git a/Hestia.Access/Requests/Product/Commands/CreateProduct/CreateProductCommand.cs b/Hestia.Access/Requests/Product/Commands/CreateProduct/CreateProductCommand.cs
index 53ce08a..031c457 100644
--- a/Hestia.Access/Requests/Product/Commands/CreateProduct/CreateProductCommand.cs
+++ b/Hestia.Access/Requests/Product/Commands/CreateProduct/CreateProductCommand.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Commands.CreateProduct;
diff --git a/Hestia.Access/Requests/Product/Commands/DeleteProduct/DeleteProductCommand.cs b/Hestia.Access/Requests/Product/Commands/DeleteProduct/DeleteProductCommand.cs
index e24e544..b2c3893 100644
--- a/Hestia.Access/Requests/Product/Commands/DeleteProduct/DeleteProductCommand.cs
+++ b/Hestia.Access/Requests/Product/Commands/DeleteProduct/DeleteProductCommand.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Commands.DeleteProduct;
diff --git a/Hestia.Access/Requests/Product/Commands/UpdateProduct/UpdateProductCommand.cs b/Hestia.Access/Requests/Product/Commands/UpdateProduct/UpdateProductCommand.cs
index a2ca5b8..d5b04e0 100644
--- a/Hestia.Access/Requests/Product/Commands/UpdateProduct/UpdateProductCommand.cs
+++ b/Hestia.Access/Requests/Product/Commands/UpdateProduct/UpdateProductCommand.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Commands.UpdateProduct;
diff --git a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByCompositeIdQuery.cs b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByCompositeIdQuery.cs
index 31bf486..2237a36 100644
--- a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByCompositeIdQuery.cs
+++ b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByCompositeIdQuery.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Queries.GetExisting;
diff --git a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByExternalIdQuery.cs b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByExternalIdQuery.cs
index 5e2909d..87ec6de 100644
--- a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByExternalIdQuery.cs
+++ b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByExternalIdQuery.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Queries.GetExisting;
diff --git a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByIdQuery.cs b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByIdQuery.cs
index ea18012..5552ba7 100644
--- a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByIdQuery.cs
+++ b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByIdQuery.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Queries.GetExisting;
diff --git a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByUserQuery.cs b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByUserQuery.cs
index 235211c..70abde2 100644
--- a/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByUserQuery.cs
+++ b/Hestia.Access/Requests/Product/Queries/GetExisting/GetExistingProductByUserQuery.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.Product.Queries.GetExisting;
diff --git a/Hestia.Access/Requests/Shared/ExecuteSaveChangesAsync.cs b/Hestia.Access/Requests/Shared/ExecuteSaveChangesAsync.cs
index c98eb63..67b2463 100644
--- a/Hestia.Access/Requests/Shared/ExecuteSaveChangesAsync.cs
+++ b/Hestia.Access/Requests/Shared/ExecuteSaveChangesAsync.cs
@@ -1,4 +1,5 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Types;
namespace Hestia.Access.Requests.Shared;
diff --git a/Hestia.Access/Requests/User/Commands/CreateUser/CreateApplicationUserCommand.cs b/Hestia.Access/Requests/User/Commands/CreateUser/CreateApplicationUserCommand.cs
index 798632c..2d9b309 100644
--- a/Hestia.Access/Requests/User/Commands/CreateUser/CreateApplicationUserCommand.cs
+++ b/Hestia.Access/Requests/User/Commands/CreateUser/CreateApplicationUserCommand.cs
@@ -1,5 +1,5 @@
using Hestia.Domain.Models.Authentication;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using Microsoft.AspNetCore.Identity;
namespace Hestia.Access.Requests.User.Commands.CreateUser;
diff --git a/Hestia.Access/Requests/User/Commands/CreateUser/CreateInternalUserCommand.cs b/Hestia.Access/Requests/User/Commands/CreateUser/CreateInternalUserCommand.cs
index 46b5d53..42759e4 100644
--- a/Hestia.Access/Requests/User/Commands/CreateUser/CreateInternalUserCommand.cs
+++ b/Hestia.Access/Requests/User/Commands/CreateUser/CreateInternalUserCommand.cs
@@ -1,4 +1,4 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.User.Commands.CreateUser;
diff --git a/Hestia.Access/Requests/User/Queries/UserExists/GetExistingUserQuery.cs b/Hestia.Access/Requests/User/Queries/UserExists/GetExistingUserQuery.cs
index 767672e..08d743c 100644
--- a/Hestia.Access/Requests/User/Queries/UserExists/GetExistingUserQuery.cs
+++ b/Hestia.Access/Requests/User/Queries/UserExists/GetExistingUserQuery.cs
@@ -1,5 +1,5 @@
using Hestia.Domain.Models.Authentication;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.User.Queries.UserExists;
diff --git a/Hestia.Access/Requests/User/Queries/ValidateUserLogin/ValidateUserLoginQuery.cs b/Hestia.Access/Requests/User/Queries/ValidateUserLogin/ValidateUserLoginQuery.cs
index 46e0c5d..1d1fab1 100644
--- a/Hestia.Access/Requests/User/Queries/ValidateUserLogin/ValidateUserLoginQuery.cs
+++ b/Hestia.Access/Requests/User/Queries/ValidateUserLogin/ValidateUserLoginQuery.cs
@@ -1,5 +1,5 @@
using Hestia.Domain.Models.Authentication;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Access.Requests.User.Queries.ValidateUserLogin;
diff --git a/Hestia.Api.Tests/Configuration/Application/ConfigureServicesTests.cs b/Hestia.Api.Tests/Configuration/Application/ConfigureServicesTests.cs
index bef9080..2a1e710 100644
--- a/Hestia.Api.Tests/Configuration/Application/ConfigureServicesTests.cs
+++ b/Hestia.Api.Tests/Configuration/Application/ConfigureServicesTests.cs
@@ -2,17 +2,18 @@
using Hestia.Api.Configuration.Application;
using Hestia.Api.Tests.Shared;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Interfaces.Response;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure;
+using Hestia.Mediator.Infrastructure.Layers;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Formatters;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
@@ -33,7 +34,10 @@ public void ConfigureApplicationServices_ShouldRegisterExpectedServices()
services.AddSingleton(new MockWebHostEnvironment { EnvironmentName = Environments.Development });
services.AddMemoryCache();
services.AddDataProtection();
- services.AddScoped();
+ services.AddDbContext(options =>
+ {
+ options.UseInMemoryDatabase("TestDb");
+ });
// Add Identity services
services.AddIdentityCore(options => { })
@@ -67,10 +71,6 @@ public void ConfigureApplicationServices_ShouldRegisterExpectedServices()
var mediator = serviceProvider.GetService();
Assert.NotNull(mediator);
- // Check if AutoMapper is registered
- var mapper = serviceProvider.GetService();
- Assert.NotNull(mapper);
-
// Check if FluentValidation validators are registered
var validators = serviceProvider.GetServices();
Assert.NotNull(validators);
diff --git a/Hestia.Api.Tests/Configuration/Extensions/WebApplicationBuilderExtensionsTests.cs b/Hestia.Api.Tests/Configuration/Extensions/WebApplicationBuilderExtensionsTests.cs
index 3845dec..cef50b7 100644
--- a/Hestia.Api.Tests/Configuration/Extensions/WebApplicationBuilderExtensionsTests.cs
+++ b/Hestia.Api.Tests/Configuration/Extensions/WebApplicationBuilderExtensionsTests.cs
@@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
@@ -35,7 +36,10 @@ public void ConfigureAuthentication_ShouldAddAuthenticationServices()
{
// Arrange
var builder = WebApplication.CreateBuilder();
- builder.Services.AddScoped();
+ builder.Services.AddDbContext(options =>
+ {
+ options.UseInMemoryDatabase("TestDb");
+ });
builder.Environment.EnvironmentName = "Development";
builder.Configuration.AddJsonFile("appsettings.json");
builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json");
diff --git a/Hestia.Api.Tests/Configuration/Infrastructure/ConfigureServicesTests.cs b/Hestia.Api.Tests/Configuration/Infrastructure/ConfigureServicesTests.cs
index bcd24c8..20070e9 100644
--- a/Hestia.Api.Tests/Configuration/Infrastructure/ConfigureServicesTests.cs
+++ b/Hestia.Api.Tests/Configuration/Infrastructure/ConfigureServicesTests.cs
@@ -2,6 +2,7 @@
using Hestia.Background.Interfaces;
using Hestia.Background.Tasks;
using Hestia.Persistence.Contexts;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -47,8 +48,15 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection ConfigureInfrastructuresServices(this IServiceCollection services)
{
- services.AddScoped();
- services.AddScoped();
+ services.AddDbContext(options =>
+ {
+ options.UseInMemoryDatabase("TestDb");
+ });
+
+ services.AddDbContext(options =>
+ {
+ options.UseInMemoryDatabase("TestDb");
+ });
services.AddMemoryCache();
services.ConfigureBackgroundRunners();
diff --git a/Hestia.Api.Tests/Hestia.Api.Tests.csproj b/Hestia.Api.Tests/Hestia.Api.Tests.csproj
index 5d0e27d..c815126 100644
--- a/Hestia.Api.Tests/Hestia.Api.Tests.csproj
+++ b/Hestia.Api.Tests/Hestia.Api.Tests.csproj
@@ -8,13 +8,20 @@
-
-
-
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Hestia.Api/Configuration/Application/ConfigureServices.cs b/Hestia.Api/Configuration/Application/ConfigureServices.cs
index bccb9e3..ca8cda6 100644
--- a/Hestia.Api/Configuration/Application/ConfigureServices.cs
+++ b/Hestia.Api/Configuration/Application/ConfigureServices.cs
@@ -1,13 +1,16 @@
using FluentValidation;
using Hestia.Application.Handlers.Validation;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Interfaces.Response;
using Hestia.Application.Services;
using Hestia.Application.Services.Authentication;
using Hestia.Application.Services.Product;
-using MediatR;
+using Hestia.Mediator.Infrastructure;
+using Hestia.Mediator.Infrastructure.Layers;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Pipeline;
+using Hestia.Mediator.Services;
using System.Reflection;
using System.Text.Json.Serialization;
@@ -22,19 +25,12 @@ public static IServiceCollection ConfigureApplicationServices(this IServiceColle
services.AddApiServices();
services.AddApplicationServices();
- // MediatR
- services.AddMediatR();
-
- // AutoMapper
- services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
+ // Mediator pattern
+ services.AddMediator();
// FluentValidation validators
services.AddFluentValidationValidators();
- // MediatR layers
- services.AddTransient();
- services.AddTransient();
-
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
@@ -43,16 +39,49 @@ public static IServiceCollection ConfigureApplicationServices(this IServiceColle
return services;
}
- public static IServiceCollection AddMediatR(this IServiceCollection services)
+ public static IServiceCollection AddMediator(this IServiceCollection services)
{
- services.AddMediatR(cfg =>
- {
- cfg.RegisterServicesFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
- });
+ // Mediator pattern service
+ services.AddSingleton();
+
+ // Mediator pattern layers
+ services.AddTransient();
+ services.AddTransient();
+
+ services.AddRequestHandlers();
return services;
}
+ private static void AddRequestHandlers(this IServiceCollection services)
+ {
+ var handlerInterfaceType = typeof(IRequestHandler<,>);
+
+ var assemblies = Directory
+ .GetFiles(AppContext.BaseDirectory, "*.dll", SearchOption.TopDirectoryOnly)
+ .Where(file =>
+ {
+ string name = Path.GetFileName(file);
+ // Adjust filter to match your solution's assemblies
+ return name.StartsWith("Hestia.", StringComparison.OrdinalIgnoreCase);
+ })
+ .Select(Assembly.LoadFrom)
+ .ToList();
+
+ var handlerTypes = assemblies
+ .SelectMany(a => a.GetTypes())
+ .Where(t => !t.IsAbstract && !t.IsInterface)
+ .SelectMany(t => t.GetInterfaces(), (type, iface) => new { type, iface })
+ .Where(x => x.iface.IsGenericType &&
+ x.iface.GetGenericTypeDefinition() == handlerInterfaceType)
+ .ToList();
+
+ foreach (var handler in handlerTypes)
+ {
+ services.AddTransient(handler.iface, handler.type);
+ }
+ }
+
public static IServiceCollection AddFluentValidationValidators(this IServiceCollection services)
{
services.AddValidatorsFromAssembly(Assembly.Load("Hestia.Domain"));
diff --git a/Hestia.Api/Configuration/Infrastructure/ConfigureServices.cs b/Hestia.Api/Configuration/Infrastructure/ConfigureServices.cs
index 363060d..8f06651 100644
--- a/Hestia.Api/Configuration/Infrastructure/ConfigureServices.cs
+++ b/Hestia.Api/Configuration/Infrastructure/ConfigureServices.cs
@@ -2,6 +2,7 @@
using Hestia.Background.Interfaces;
using Hestia.Background.Tasks;
using Hestia.Persistence.Contexts;
+using Microsoft.EntityFrameworkCore;
namespace Hestia.Api.Configuration.Infrastructure;
@@ -27,8 +28,17 @@ private static IServiceCollection ConfigureBackgroundRunners(this IServiceCollec
private static IServiceCollection ConfigureDbContexts(this IServiceCollection services)
{
- services.AddScoped();
- services.AddScoped();
+ services.AddDbContext((serviceProvider, options) =>
+ {
+ var configuration = serviceProvider.GetRequiredService();
+ options.UseNpgsql(configuration.GetConnectionString("AuthServer"));
+ });
+
+ services.AddDbContext((serviceProvider, options) =>
+ {
+ var configuration = serviceProvider.GetRequiredService();
+ options.UseNpgsql(configuration.GetConnectionString("DataServer"));
+ });
return services;
}
diff --git a/Hestia.Api/Controllers/AuthenticationController.cs b/Hestia.Api/Controllers/AuthenticationController.cs
index 8412077..bbaf7d3 100644
--- a/Hestia.Api/Controllers/AuthenticationController.cs
+++ b/Hestia.Api/Controllers/AuthenticationController.cs
@@ -1,9 +1,9 @@
using Hestia.Application.Handlers.Authentication.Commands.Login;
using Hestia.Application.Handlers.Authentication.Commands.Register;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Models.Shared;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.AspNetCore.Mvc;
namespace Hestia.Api.Controllers;
diff --git a/Hestia.Api/Controllers/ProductController.cs b/Hestia.Api/Controllers/ProductController.cs
index ee72733..3e659c9 100644
--- a/Hestia.Api/Controllers/ProductController.cs
+++ b/Hestia.Api/Controllers/ProductController.cs
@@ -2,11 +2,11 @@
using Hestia.Application.Handlers.Product.Commands.DeleteProduct;
using Hestia.Application.Handlers.Product.Commands.UpdateProduct;
using Hestia.Application.Handlers.Product.Queries.GetProduct;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.CreateProduct;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
diff --git a/Hestia.Api/Hestia.Api.csproj b/Hestia.Api/Hestia.Api.csproj
index d2bf889..88377bf 100644
--- a/Hestia.Api/Hestia.Api.csproj
+++ b/Hestia.Api/Hestia.Api.csproj
@@ -14,25 +14,27 @@
-
-
-
-
-
-
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
-
+
+
+
+
diff --git a/Hestia.Application/Models/Authentication/Inbound/ApplicationUserLoginDto.cs b/Hestia.Application.Models/Authentication/Inbound/ApplicationUserLoginDto.cs
similarity index 100%
rename from Hestia.Application/Models/Authentication/Inbound/ApplicationUserLoginDto.cs
rename to Hestia.Application.Models/Authentication/Inbound/ApplicationUserLoginDto.cs
diff --git a/Hestia.Application/Models/Authentication/Inbound/ApplicationUserRegisterDto.cs b/Hestia.Application.Models/Authentication/Inbound/ApplicationUserRegisterDto.cs
similarity index 100%
rename from Hestia.Application/Models/Authentication/Inbound/ApplicationUserRegisterDto.cs
rename to Hestia.Application.Models/Authentication/Inbound/ApplicationUserRegisterDto.cs
diff --git a/Hestia.Application/Models/Authentication/Inbound/ApplicationUserRegisterDtoValidator.cs b/Hestia.Application.Models/Authentication/Inbound/ApplicationUserRegisterDtoValidator.cs
similarity index 100%
rename from Hestia.Application/Models/Authentication/Inbound/ApplicationUserRegisterDtoValidator.cs
rename to Hestia.Application.Models/Authentication/Inbound/ApplicationUserRegisterDtoValidator.cs
diff --git a/Hestia.Application/Models/Authentication/Outbound/ApplicationUserLoginResponseDto.cs b/Hestia.Application.Models/Authentication/Outbound/ApplicationUserLoginResponseDto.cs
similarity index 100%
rename from Hestia.Application/Models/Authentication/Outbound/ApplicationUserLoginResponseDto.cs
rename to Hestia.Application.Models/Authentication/Outbound/ApplicationUserLoginResponseDto.cs
diff --git a/Hestia.Application/Models/Authentication/Outbound/ApplicationUserRegisterResponseDto.cs b/Hestia.Application.Models/Authentication/Outbound/ApplicationUserRegisterResponseDto.cs
similarity index 100%
rename from Hestia.Application/Models/Authentication/Outbound/ApplicationUserRegisterResponseDto.cs
rename to Hestia.Application.Models/Authentication/Outbound/ApplicationUserRegisterResponseDto.cs
diff --git a/Hestia.Application.Models/Hestia.Application.Models.csproj b/Hestia.Application.Models/Hestia.Application.Models.csproj
new file mode 100644
index 0000000..31bf826
--- /dev/null
+++ b/Hestia.Application.Models/Hestia.Application.Models.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Hestia.Application/Models/Shared/ApiResponse.cs b/Hestia.Application.Models/Shared/ApiResponse.cs
similarity index 100%
rename from Hestia.Application/Models/Shared/ApiResponse.cs
rename to Hestia.Application.Models/Shared/ApiResponse.cs
diff --git a/Hestia.Application/Models/Shared/AppSettings.cs b/Hestia.Application.Models/Shared/AppSettings.cs
similarity index 100%
rename from Hestia.Application/Models/Shared/AppSettings.cs
rename to Hestia.Application.Models/Shared/AppSettings.cs
diff --git a/Hestia.Application.Tests/Hestia.Application.Tests.csproj b/Hestia.Application.Tests/Hestia.Application.Tests.csproj
index ea778b7..a50c58b 100644
--- a/Hestia.Application.Tests/Hestia.Application.Tests.csproj
+++ b/Hestia.Application.Tests/Hestia.Application.Tests.csproj
@@ -8,16 +8,23 @@
-
-
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/Hestia.Application.Tests/Profiles/Authentication/ApplicationUserProfileTests.cs b/Hestia.Application.Tests/Profiles/Authentication/ApplicationUserProfileTests.cs
index 680c8f1..55a6e29 100644
--- a/Hestia.Application.Tests/Profiles/Authentication/ApplicationUserProfileTests.cs
+++ b/Hestia.Application.Tests/Profiles/Authentication/ApplicationUserProfileTests.cs
@@ -1,6 +1,4 @@
-using AutoMapper;
-using Hestia.Application.Models.Authentication.Outbound;
-using Hestia.Application.Profiles.Authentication;
+using Hestia.Application.Mappers;
using Hestia.Domain.Enumerations;
using Hestia.Domain.Models.Authentication;
@@ -8,28 +6,6 @@ namespace Hestia.Application.Tests.Profiles.Authentication;
public class ApplicationUserProfileTests
{
- private readonly IMapper _mapper;
-
- public ApplicationUserProfileTests()
- {
- var config = new MapperConfiguration(cfg =>
- {
- cfg.AddProfile();
- });
- _mapper = config.CreateMapper();
- }
-
- [Fact]
- public void ApplicationUserProfile_ConfigurationIsValid()
- {
- var config = new MapperConfiguration(cfg =>
- {
- cfg.AddProfile();
- });
-
- config.AssertConfigurationIsValid();
- }
-
[Fact]
public void ApplicationUser_To_ApplicationUserRegisterResponseDto_Mapping()
{
@@ -43,30 +19,10 @@ public void ApplicationUser_To_ApplicationUserRegisterResponseDto_Mapping()
};
// Act
- var registerResponseDto = _mapper.Map(applicationUser);
+ var registerResponseDto = applicationUser.ToRegisterResponseDto();
// Assert
Assert.Equal(applicationUser.UserName, registerResponseDto.Username);
Assert.Equal(applicationUser.Email, registerResponseDto.Email);
}
-
- [Fact]
- public void ApplicationUser_To_ApplicationUserLoginResponseDto_Mapping()
- {
- // Arrange
- var applicationUser = new ApplicationUser
- {
- Id = "1",
- UserName = "testuser",
- Email = "test@example.com",
- Role = Role.User
- };
-
- // Act
- var loginResponseDto = _mapper.Map(applicationUser);
-
- // Assert
- Assert.Equal(applicationUser.UserName, loginResponseDto.Username);
- Assert.Equal(applicationUser.Email, loginResponseDto.Email);
- }
}
\ No newline at end of file
diff --git a/Hestia.Application.Tests/Profiles/Product/ProductProfileTests.cs b/Hestia.Application.Tests/Profiles/Product/ProductProfileTests.cs
index ada6619..3b2b3dc 100644
--- a/Hestia.Application.Tests/Profiles/Product/ProductProfileTests.cs
+++ b/Hestia.Application.Tests/Profiles/Product/ProductProfileTests.cs
@@ -1,34 +1,10 @@
-using AutoMapper;
-using Hestia.Application.Profiles.Product;
-using Hestia.Domain.Models.Product.Inbound.GetProduct;
+using Hestia.Application.Mappers;
using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
namespace Hestia.Application.Tests.Profiles.Product;
public class ProductProfileTests
{
- private readonly IMapper _mapper;
-
- public ProductProfileTests()
- {
- var config = new MapperConfiguration(cfg =>
- {
- cfg.AddProfile();
- });
- _mapper = config.CreateMapper();
- }
-
- [Fact]
- public void ProductProfile_ConfigurationIsValid()
- {
- var config = new MapperConfiguration(cfg =>
- {
- cfg.AddProfile();
- });
-
- config.AssertConfigurationIsValid();
- }
-
[Fact]
public void UpdateProductDto_To_Product_Mapping()
{
@@ -41,26 +17,27 @@ public void UpdateProductDto_To_Product_Mapping()
Description = "UpdatedDescription",
Price = 99.99M
};
- var product = new Access.Entities.Product.Product(Guid.NewGuid())
+
+ var product = new Access.Entities.Product.Product(updateProductDto.Id)
{
- ExternalId = "originalExternalId",
+ ExternalId = updateProductDto.ExternalId,
DateCreated = DateTime.UtcNow.AddDays(-1),
- Name = "UpdatedName",
- Description = "UpdatedDescription",
- Price = 99.99M,
+ Name = "OriginalName",
+ Description = "OriginalDescription",
+ Price = 10.00M,
UserId = "UserId"
};
// Act
- var mappedProduct = _mapper.Map(updateProductDto, product);
+ product.ApplyUpdate(updateProductDto);
// Assert
- Assert.Equal(product.Id, mappedProduct.Id);
- Assert.Equal(product.ExternalId, mappedProduct.ExternalId);
- Assert.Equal(product.DateCreated, mappedProduct.DateCreated);
- Assert.Equal(updateProductDto.Name, mappedProduct.Name);
- Assert.Equal(updateProductDto.Description, mappedProduct.Description);
- Assert.Equal(updateProductDto.Price, mappedProduct.Price);
+ Assert.Equal(updateProductDto.Id, product.Id);
+ Assert.Equal(updateProductDto.ExternalId, product.ExternalId);
+ Assert.Equal(updateProductDto.Name, product.Name);
+ Assert.Equal(updateProductDto.Description, product.Description);
+ Assert.Equal(updateProductDto.Price, product.Price);
+ Assert.True(product.DateEdited > product.DateCreated);
}
[Fact]
@@ -71,7 +48,7 @@ public void Product_To_GetProductResponseDto_Mapping()
{
ExternalId = "originalExternalId",
DateCreated = DateTime.UtcNow.AddDays(-1),
- DateEdited = DateTime.UtcNow.AddDays(-1),
+ DateEdited = DateTime.UtcNow,
Name = "UpdatedName",
Description = "UpdatedDescription",
Price = 99.99M,
@@ -79,13 +56,15 @@ public void Product_To_GetProductResponseDto_Mapping()
};
// Act
- var productResponseDto = _mapper.Map(product);
+ var productResponseDto = product.ToResponseDto();
// Assert
Assert.Equal(product.Id, productResponseDto.Id);
Assert.Equal(product.ExternalId, productResponseDto.ExternalId);
+ Assert.Equal(product.DateCreated, productResponseDto.DateCreated);
+ Assert.Equal(product.DateEdited, productResponseDto.DateEdited);
Assert.Equal(product.Name, productResponseDto.Name);
Assert.Equal(product.Description, productResponseDto.Description);
Assert.Equal(product.Price, productResponseDto.Price);
}
-}
\ No newline at end of file
+}
diff --git a/Hestia.Application.Tests/Services/Authentication/AuthServiceTests.cs b/Hestia.Application.Tests/Services/Authentication/AuthServiceTests.cs
index a94fb25..cadc59a 100644
--- a/Hestia.Application.Tests/Services/Authentication/AuthServiceTests.cs
+++ b/Hestia.Application.Tests/Services/Authentication/AuthServiceTests.cs
@@ -1,12 +1,10 @@
-using AutoMapper;
-using Hestia.Access.Requests.User.Queries.UserExists;
+using Hestia.Access.Requests.User.Queries.UserExists;
using Hestia.Access.Requests.User.Queries.ValidateUserLogin;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Authentication.Inbound;
-using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Services.Authentication;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.Extensions.Logging;
using Moq;
using System.Net;
@@ -17,7 +15,6 @@ public class AuthServiceTests
{
private readonly Mock _mockTokenService;
private readonly Mock _mockUserService;
- private readonly Mock _mockMapper;
private readonly Mock _mockAccessLayer;
private readonly Mock> _mockLogger;
private readonly AuthService _authService;
@@ -26,13 +23,11 @@ public AuthServiceTests()
{
_mockTokenService = new Mock();
_mockUserService = new Mock();
- _mockMapper = new Mock();
_mockAccessLayer = new Mock();
_mockLogger = new Mock>();
_authService = new AuthService(
_mockTokenService.Object,
_mockUserService.Object,
- _mockMapper.Object,
_mockAccessLayer.Object,
_mockLogger.Object
);
@@ -111,21 +106,18 @@ public async Task RegisterAsync_ShouldReturnCreated_WhenUserIsRegisteredSuccessf
var newUser = new ApplicationUser { UserName = "newuser", Email = "newuser@example.com" };
_mockAccessLayer.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny()))
- .ReturnsAsync((ApplicationUser)null);
+ .ReturnsAsync(null as ApplicationUser);
_mockUserService.Setup(x => x.CreateUserAsync(model, It.IsAny()))
.ReturnsAsync(newUser);
- _mockMapper.Setup(m => m.Map(It.IsAny()))
- .Returns(new ApplicationUserRegisterResponseDto { Username = "newuser", Email = "newuser@example.com" });
-
// Act
var (response, statusCode) = await _authService.RegisterAsync(model);
// Assert
Assert.Equal(HttpStatusCode.Created, statusCode);
- Assert.Equal("newuser", response.Username);
- Assert.Equal("newuser@example.com", response.Email);
+ Assert.Equal("newuser", response?.Username);
+ Assert.Equal("newuser@example.com", response?.Email);
}
[Fact]
diff --git a/Hestia.Application.Tests/Services/Authentication/TokenServiceTests.cs b/Hestia.Application.Tests/Services/Authentication/TokenServiceTests.cs
index a67eef1..f79a8ec 100644
--- a/Hestia.Application.Tests/Services/Authentication/TokenServiceTests.cs
+++ b/Hestia.Application.Tests/Services/Authentication/TokenServiceTests.cs
@@ -1,10 +1,10 @@
using Hestia.Access.Requests.Authentication.Commands.CreateTokenLog;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Shared;
using Hestia.Application.Services.Authentication;
using Hestia.Domain.Enumerations;
using Hestia.Domain.Models.Authentication;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Layers;
+using Hestia.Mediator.Infrastructure.Types;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
diff --git a/Hestia.Application.Tests/Services/Authentication/UserServiceTests.cs b/Hestia.Application.Tests/Services/Authentication/UserServiceTests.cs
index 8abe83b..5171091 100644
--- a/Hestia.Application.Tests/Services/Authentication/UserServiceTests.cs
+++ b/Hestia.Application.Tests/Services/Authentication/UserServiceTests.cs
@@ -1,9 +1,9 @@
using Hestia.Access.Requests.User.Commands.CreateUser;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Application.Services.Authentication;
using Hestia.Domain.Enumerations;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.AspNetCore.Identity;
using Moq;
diff --git a/Hestia.Application.Tests/Services/Product/ProductServiceTests.cs b/Hestia.Application.Tests/Services/Product/ProductServiceTests.cs
index d7d2ed4..ec2fbd9 100644
--- a/Hestia.Application.Tests/Services/Product/ProductServiceTests.cs
+++ b/Hestia.Application.Tests/Services/Product/ProductServiceTests.cs
@@ -1,13 +1,12 @@
-using AutoMapper;
-using Hestia.Access.Requests.Product.Commands.CreateProduct;
+using Hestia.Access.Requests.Product.Commands.CreateProduct;
using Hestia.Access.Requests.Product.Commands.DeleteProduct;
using Hestia.Access.Requests.Product.Commands.UpdateProduct;
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Services.Product;
using Hestia.Domain.Models.Product.Inbound.CreateProduct;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.Extensions.Logging;
using Moq;
using System.Net;
@@ -17,16 +16,14 @@ namespace Hestia.Application.Tests.Services.Product;
public class ProductServiceCreateProductTests
{
private readonly Mock _mockAccessLayer;
- private readonly Mock _mockMapper;
private readonly Mock> _mockLogger;
private readonly ProductService _productService;
public ProductServiceCreateProductTests()
{
_mockAccessLayer = new Mock();
- _mockMapper = new Mock();
_mockLogger = new Mock>();
- _productService = new ProductService(_mockAccessLayer.Object, _mockMapper.Object, _mockLogger.Object);
+ _productService = new ProductService(_mockAccessLayer.Object, _mockLogger.Object);
}
[Fact]
@@ -139,8 +136,6 @@ public async Task UpdateProductAsync_ShouldReturnOk_WhenProductIsUpdatedSuccessf
_mockAccessLayer.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny()))
.ReturnsAsync(true);
- _mockMapper.Setup(m => m.Map(updateProductDto, existingProduct)).Returns(existingProduct);
-
// Act
var (isUpdated, statusCode) = await _productService.UpdateProductAsync(updateProductDto);
@@ -304,8 +299,6 @@ public async Task GetProductAsync_ShouldReturnOk_WhenProductIsFound()
_mockAccessLayer.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny()))
.ReturnsAsync(existingProduct);
- _mockMapper.Setup(m => m.Map(existingProduct)).Returns(getProductResponseDto);
-
// Act
var (productResponse, statusCode) = await _productService.GetProductAsync(getProductDto);
diff --git a/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommand.cs b/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommand.cs
index 66f1610..2ea67c3 100644
--- a/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommand.cs
+++ b/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommand.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Authentication.Commands.Login;
diff --git a/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommandHandler.cs b/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommandHandler.cs
index 3d6595f..1944945 100644
--- a/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommandHandler.cs
+++ b/Hestia.Application/Handlers/Authentication/Commands/Login/ApplicationUserLoginCommandHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Interfaces.Authentication;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Authentication.Commands.Login;
diff --git a/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommand.cs b/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommand.cs
index d4b1ac6..135c333 100644
--- a/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommand.cs
+++ b/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommand.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Authentication.Commands.Register;
diff --git a/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommandHandler.cs b/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommandHandler.cs
index c172152..5cde267 100644
--- a/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommandHandler.cs
+++ b/Hestia.Application/Handlers/Authentication/Commands/Register/ApplicationUserRegisterCommandHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Interfaces.Authentication;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Authentication.Commands.Register;
diff --git a/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommand.cs b/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommand.cs
index 74725c2..5dfd001 100644
--- a/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommand.cs
+++ b/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommand.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.CreateProduct;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Product.Commands.CreateProduct;
diff --git a/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs b/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
index 3935d79..9764fac 100644
--- a/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
+++ b/Hestia.Application/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Interfaces.Authentication;
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Product.Commands.CreateProduct;
diff --git a/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommand.cs b/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommand.cs
index a4afe89..02a0414 100644
--- a/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommand.cs
+++ b/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommand.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Product.Commands.DeleteProduct;
diff --git a/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs b/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
index 7927a1b..407b963 100644
--- a/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
+++ b/Hestia.Application/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Product.Commands.DeleteProduct;
diff --git a/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommand.cs b/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommand.cs
index 92f0eb2..1c4f0a0 100644
--- a/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommand.cs
+++ b/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommand.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Product.Commands.UpdateProduct;
diff --git a/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs b/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
index 8bd3a2a..6af07ea 100644
--- a/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
+++ b/Hestia.Application/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Models.Shared;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Product.Commands.UpdateProduct;
diff --git a/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQuery.cs b/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQuery.cs
index e9c1613..ed3fd34 100644
--- a/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQuery.cs
+++ b/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQuery.cs
@@ -1,6 +1,6 @@
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
namespace Hestia.Application.Handlers.Product.Queries.GetProduct;
diff --git a/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQueryHandler.cs b/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQueryHandler.cs
index 0bd56d7..11a813b 100644
--- a/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQueryHandler.cs
+++ b/Hestia.Application/Handlers/Product/Queries/GetProduct/GetProductQueryHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Application.Interfaces.Product;
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using System.Net;
namespace Hestia.Application.Handlers.Product.Queries.GetProduct;
diff --git a/Hestia.Application/Handlers/Validation/ValidationBehavior.cs b/Hestia.Application/Handlers/Validation/ValidationBehavior.cs
index b26fc83..2165b1c 100644
--- a/Hestia.Application/Handlers/Validation/ValidationBehavior.cs
+++ b/Hestia.Application/Handlers/Validation/ValidationBehavior.cs
@@ -1,13 +1,17 @@
using FluentValidation;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Pipeline;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Reflection;
namespace Hestia.Application.Handlers.Validation;
-public class ValidationBehavior(IEnumerable> validators, IServiceProvider serviceProvider, ILogger> logger)
- : IPipelineBehavior where TRequest : IRequest
+public class ValidationBehavior(
+ IEnumerable> validators,
+ IServiceProvider serviceProvider,
+ ILogger> logger) :
+ IPipelineBehavior where TRequest : IRequest
{
public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken)
{
diff --git a/Hestia.Application/Hestia.Application.csproj b/Hestia.Application/Hestia.Application.csproj
index 5e73513..aa30e87 100644
--- a/Hestia.Application/Hestia.Application.csproj
+++ b/Hestia.Application/Hestia.Application.csproj
@@ -7,18 +7,18 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Hestia.Application/Interfaces/Infrastructure/IAccessLayer.cs b/Hestia.Application/Interfaces/Infrastructure/IAccessLayer.cs
deleted file mode 100644
index 47b1a68..0000000
--- a/Hestia.Application/Interfaces/Infrastructure/IAccessLayer.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace Hestia.Application.Interfaces.Infrastructure;
-
-public interface IAccessLayer : IRequestExecutor;
\ No newline at end of file
diff --git a/Hestia.Application/Interfaces/Infrastructure/ICoreLayer.cs b/Hestia.Application/Interfaces/Infrastructure/ICoreLayer.cs
deleted file mode 100644
index 1e99476..0000000
--- a/Hestia.Application/Interfaces/Infrastructure/ICoreLayer.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace Hestia.Application.Interfaces.Infrastructure;
-
-public interface ICoreLayer : IRequestExecutor;
\ No newline at end of file
diff --git a/Hestia.Application/Profiles/Authentication/ApplicationUserProfile.cs b/Hestia.Application/Profiles/Authentication/ApplicationUserProfile.cs
deleted file mode 100644
index 26795e7..0000000
--- a/Hestia.Application/Profiles/Authentication/ApplicationUserProfile.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using AutoMapper;
-using Hestia.Application.Models.Authentication.Outbound;
-using Hestia.Domain.Models.Authentication;
-
-namespace Hestia.Application.Profiles.Authentication;
-
-public class ApplicationUserProfile : Profile
-{
- public ApplicationUserProfile()
- {
- CreateMap();
- CreateMap()
- .ForMember(dest => dest.Token, opt => opt.Ignore());
- }
-}
\ No newline at end of file
diff --git a/Hestia.Application/Profiles/Product/ProductProfile.cs b/Hestia.Application/Profiles/Product/ProductProfile.cs
deleted file mode 100644
index 65c9904..0000000
--- a/Hestia.Application/Profiles/Product/ProductProfile.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using AutoMapper;
-using Hestia.Domain.Models.Product.Inbound.GetProduct;
-using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
-
-namespace Hestia.Application.Profiles.Product;
-
-public class ProductProfile : Profile
-{
- public ProductProfile()
- {
- CreateMap()
- .ForMember(dest => dest.Id, opt => opt.Ignore())
- .ForMember(dest => dest.ExternalId, opt => opt.Ignore())
- .ForMember(dest => dest.DateCreated, opt => opt.Ignore())
- .ForMember(dest => dest.UserId, opt => opt.Ignore())
- .ForMember(dest => dest.DateEdited, opt => opt.MapFrom(src => DateTime.UtcNow))
- .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
-
- CreateMap();
- }
-}
\ No newline at end of file
diff --git a/Hestia.Application/Services/Authentication/AuthService.cs b/Hestia.Application/Services/Authentication/AuthService.cs
index 1175367..64a2cfe 100644
--- a/Hestia.Application/Services/Authentication/AuthService.cs
+++ b/Hestia.Application/Services/Authentication/AuthService.cs
@@ -1,13 +1,13 @@
-using AutoMapper;
-using Hestia.Access.Requests.Shared;
+using Hestia.Access.Requests.Shared;
using Hestia.Access.Requests.User.Queries.UserExists;
using Hestia.Access.Requests.User.Queries.ValidateUserLogin;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
+using Hestia.Application.Mappers;
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Application.Models.Authentication.Outbound;
using Hestia.Domain.Enumerations;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.Extensions.Logging;
using System.Net;
@@ -16,19 +16,17 @@ namespace Hestia.Application.Services.Authentication;
public class AuthService(
ITokenService tokenService,
IUserService userService,
- IMapper mapper,
IAccessLayer accessLayer,
ILogger logger) : IAuthService
{
public async Task<(ApplicationUserLoginResponseDto, HttpStatusCode)> LoginAsync(ApplicationUserLoginDto model, CancellationToken cancellationToken = default)
{
string? token = null!;
- ApplicationUser? existingUser = null;
- var statusCode = HttpStatusCode.NoContent;
+ HttpStatusCode statusCode;
try
{
- existingUser = await GetExistingUserAsync(model.Username, model.Email, cancellationToken);
+ var existingUser = await GetExistingUserAsync(model.Username, model.Email, cancellationToken);
if (existingUser is null)
{
@@ -55,7 +53,7 @@ public class AuthService(
return (response, statusCode);
}
- public async Task<(ApplicationUserRegisterResponseDto, HttpStatusCode)> RegisterAsync(ApplicationUserRegisterDto model, Role? role = null, CancellationToken cancellationToken = default)
+ public async Task<(ApplicationUserRegisterResponseDto?, HttpStatusCode)> RegisterAsync(ApplicationUserRegisterDto model, Role? role = null, CancellationToken cancellationToken = default)
{
ApplicationUser? existingUser = null;
var statusCode = HttpStatusCode.NoContent;
@@ -83,7 +81,7 @@ public class AuthService(
statusCode = HttpStatusCode.InternalServerError;
}
- var response = mapper.Map(existingUser);
+ var response = existingUser?.ToRegisterResponseDto();
return (response, statusCode);
}
diff --git a/Hestia.Application/Services/Authentication/TokenService.cs b/Hestia.Application/Services/Authentication/TokenService.cs
index 2979217..b4effce 100644
--- a/Hestia.Application/Services/Authentication/TokenService.cs
+++ b/Hestia.Application/Services/Authentication/TokenService.cs
@@ -1,8 +1,8 @@
using Hestia.Access.Requests.Authentication.Commands.CreateTokenLog;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Shared;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
diff --git a/Hestia.Application/Services/Authentication/UserService.cs b/Hestia.Application/Services/Authentication/UserService.cs
index 6cdf693..e78e434 100644
--- a/Hestia.Application/Services/Authentication/UserService.cs
+++ b/Hestia.Application/Services/Authentication/UserService.cs
@@ -1,9 +1,9 @@
using Hestia.Access.Entities.User;
using Hestia.Access.Requests.User.Commands.CreateUser;
using Hestia.Application.Interfaces.Authentication;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Models.Authentication.Inbound;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.AspNetCore.Identity;
namespace Hestia.Application.Services.Authentication;
diff --git a/Hestia.Application/Services/Product/ProductService.cs b/Hestia.Application/Services/Product/ProductService.cs
index 7f7a1b4..6df1b6f 100644
--- a/Hestia.Application/Services/Product/ProductService.cs
+++ b/Hestia.Application/Services/Product/ProductService.cs
@@ -1,19 +1,19 @@
-using AutoMapper;
-using Hestia.Access.Requests.Product.Commands.CreateProduct;
+using Hestia.Access.Requests.Product.Commands.CreateProduct;
using Hestia.Access.Requests.Product.Commands.DeleteProduct;
using Hestia.Access.Requests.Product.Commands.UpdateProduct;
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Application.Interfaces.Infrastructure;
using Hestia.Application.Interfaces.Product;
+using Hestia.Application.Mappers;
using Hestia.Domain.Models.Product.Inbound.CreateProduct;
using Hestia.Domain.Models.Product.Inbound.GetProduct;
using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
+using Hestia.Mediator.Infrastructure.Layers;
using Microsoft.Extensions.Logging;
using System.Net;
namespace Hestia.Application.Services.Product;
-public class ProductService(IAccessLayer accessLayer, IMapper mapper, ILogger logger) : IProductService
+public class ProductService(IAccessLayer accessLayer, ILogger logger) : IProductService
{
public async Task<(Guid?, HttpStatusCode)> CreateProductAsync(CreateProductDto product, CancellationToken cancellationToken = default)
{
@@ -45,7 +45,7 @@ public class ProductService(IAccessLayer accessLayer, IMapper mapper, ILogger(existingProduct), HttpStatusCode.OK);
+ (existingProduct.ToResponseDto(), HttpStatusCode.OK);
}
catch (Exception ex)
{
@@ -114,7 +114,7 @@ public class ProductService(IAccessLayer accessLayer, IMapper mapper, ILogger GetExistingProductAsync(GetProductDto product, CancellationToken cancellationToken = default) =>
product.Id.HasValue && product.Id != Guid.Empty && !string.IsNullOrEmpty(product.ExternalId) ?
await GetExistingProductAsync((Guid)product.Id, product.ExternalId, cancellationToken) :
- !product.Id.HasValue || product.Id == Guid.Empty ?
+ (!product.Id.HasValue || product.Id == Guid.Empty) && !string.IsNullOrEmpty(product.ExternalId) ?
await GetExistingProductAsync(product.ExternalId, cancellationToken) :
string.IsNullOrEmpty(product.ExternalId) ?
await GetExistingProductAsync(product.Id, cancellationToken) : null;
diff --git a/Hestia.Background/Hestia.Background.csproj b/Hestia.Background/Hestia.Background.csproj
index 636040b..d6837c6 100644
--- a/Hestia.Background/Hestia.Background.csproj
+++ b/Hestia.Background/Hestia.Background.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/Hestia.Domain/Hestia.Domain.csproj b/Hestia.Domain/Hestia.Domain.csproj
index 01539f1..3c6b686 100644
--- a/Hestia.Domain/Hestia.Domain.csproj
+++ b/Hestia.Domain/Hestia.Domain.csproj
@@ -7,9 +7,8 @@
-
-
-
+
+
diff --git a/Hestia.Mapper/Hestia.Mapper.csproj b/Hestia.Mapper/Hestia.Mapper.csproj
new file mode 100644
index 0000000..bc7da11
--- /dev/null
+++ b/Hestia.Mapper/Hestia.Mapper.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/Hestia.Mapper/Mapper.cs b/Hestia.Mapper/Mapper.cs
new file mode 100644
index 0000000..a03d33e
--- /dev/null
+++ b/Hestia.Mapper/Mapper.cs
@@ -0,0 +1,5 @@
+namespace Hestia.Application.Mappers;
+
+public static partial class Mapper
+{
+}
\ No newline at end of file
diff --git a/Hestia.Mapper/Mappers/ApplicationUser.cs b/Hestia.Mapper/Mappers/ApplicationUser.cs
new file mode 100644
index 0000000..f62bf7b
--- /dev/null
+++ b/Hestia.Mapper/Mappers/ApplicationUser.cs
@@ -0,0 +1,17 @@
+using Hestia.Application.Models.Authentication.Outbound;
+using Hestia.Domain.Models.Authentication;
+
+namespace Hestia.Application.Mappers;
+
+public static partial class Mapper
+{
+ public static ApplicationUserRegisterResponseDto ToRegisterResponseDto(this ApplicationUser user)
+ {
+ return new ApplicationUserRegisterResponseDto
+ {
+ Username = user.UserName,
+ Email = user.Email,
+ Role = user.Role
+ };
+ }
+}
\ No newline at end of file
diff --git a/Hestia.Mapper/Mappers/Product.cs b/Hestia.Mapper/Mappers/Product.cs
new file mode 100644
index 0000000..2ac3438
--- /dev/null
+++ b/Hestia.Mapper/Mappers/Product.cs
@@ -0,0 +1,30 @@
+using Hestia.Access.Entities.Product;
+using Hestia.Domain.Models.Product.Inbound.GetProduct;
+using Hestia.Domain.Models.Product.Inbound.UpdateProduct;
+
+namespace Hestia.Application.Mappers;
+
+public static partial class Mapper
+{
+ public static void ApplyUpdate(this Product product, UpdateProductDto dto)
+ {
+ product.Name = dto.Name;
+ product.Description = dto.Description;
+ product.Price = dto.Price;
+ product.DateEdited = DateTime.UtcNow;
+ }
+
+ public static GetProductResponseDto ToResponseDto(this Product product)
+ {
+ return new GetProductResponseDto
+ {
+ Id = product.Id,
+ ExternalId = product.ExternalId,
+ DateCreated = product.DateCreated,
+ Name = product.Name,
+ Description = product.Description,
+ Price = product.Price,
+ DateEdited = product.DateEdited
+ };
+ }
+}
\ No newline at end of file
diff --git a/Hestia.Mediator/Hestia.Mediator.csproj b/Hestia.Mediator/Hestia.Mediator.csproj
new file mode 100644
index 0000000..bf177e5
--- /dev/null
+++ b/Hestia.Mediator/Hestia.Mediator.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Hestia.Mediator/Infrastructure/IMediator.cs b/Hestia.Mediator/Infrastructure/IMediator.cs
new file mode 100644
index 0000000..3f37bc4
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/IMediator.cs
@@ -0,0 +1,9 @@
+using Hestia.Mediator.Infrastructure.Messaging;
+
+namespace Hestia.Mediator.Infrastructure;
+
+public interface IMediator
+{
+ Task Send(IRequest request, CancellationToken cancellationToken = default);
+ Task Send(IRequest request, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/Hestia.Application/Interfaces/Infrastructure/IRequestExecutor.cs b/Hestia.Mediator/Infrastructure/IRequestExecutor.cs
similarity index 75%
rename from Hestia.Application/Interfaces/Infrastructure/IRequestExecutor.cs
rename to Hestia.Mediator/Infrastructure/IRequestExecutor.cs
index aadc1fb..9b2d119 100644
--- a/Hestia.Application/Interfaces/Infrastructure/IRequestExecutor.cs
+++ b/Hestia.Mediator/Infrastructure/IRequestExecutor.cs
@@ -1,6 +1,6 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
-namespace Hestia.Application.Interfaces.Infrastructure;
+namespace Hestia.Mediator.Infrastructure;
public interface IRequestExecutor
{
diff --git a/Hestia.Mediator/Infrastructure/Layers/IAccessLayer.cs b/Hestia.Mediator/Infrastructure/Layers/IAccessLayer.cs
new file mode 100644
index 0000000..aa5da43
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/Layers/IAccessLayer.cs
@@ -0,0 +1,3 @@
+namespace Hestia.Mediator.Infrastructure.Layers;
+
+public interface IAccessLayer : IRequestExecutor;
\ No newline at end of file
diff --git a/Hestia.Mediator/Infrastructure/Layers/ICoreLayer.cs b/Hestia.Mediator/Infrastructure/Layers/ICoreLayer.cs
new file mode 100644
index 0000000..19f6eda
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/Layers/ICoreLayer.cs
@@ -0,0 +1,3 @@
+namespace Hestia.Mediator.Infrastructure.Layers;
+
+public interface ICoreLayer : IRequestExecutor;
\ No newline at end of file
diff --git a/Hestia.Application/Interfaces/Infrastructure/MediatrAdapter.cs b/Hestia.Mediator/Infrastructure/MediatorAdapter.cs
similarity index 55%
rename from Hestia.Application/Interfaces/Infrastructure/MediatrAdapter.cs
rename to Hestia.Mediator/Infrastructure/MediatorAdapter.cs
index 3911504..cd74ff3 100644
--- a/Hestia.Application/Interfaces/Infrastructure/MediatrAdapter.cs
+++ b/Hestia.Mediator/Infrastructure/MediatorAdapter.cs
@@ -1,15 +1,13 @@
-using MediatR;
+using Hestia.Mediator.Infrastructure.Layers;
+using Hestia.Mediator.Infrastructure.Messaging;
-namespace Hestia.Application.Interfaces.Infrastructure;
+namespace Hestia.Mediator.Infrastructure;
-public class MediatrAdapter(IMediator mediator) : IAccessLayer, ICoreLayer
+public class MediatorAdapter(IMediator mediator) : IAccessLayer, ICoreLayer
{
public Task ExecuteAsync(IRequest request, CancellationToken cancellationToken = default) =>
mediator.Send(request, cancellationToken);
public Task ExecuteAsync(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest =>
mediator.Send(request, cancellationToken);
-
- public Task PublishAsync(TNotification notification) where TNotification : INotification =>
- mediator.Publish(notification);
}
\ No newline at end of file
diff --git a/Hestia.Mediator/Infrastructure/Messaging/IRequest.cs b/Hestia.Mediator/Infrastructure/Messaging/IRequest.cs
new file mode 100644
index 0000000..b247e18
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/Messaging/IRequest.cs
@@ -0,0 +1,11 @@
+namespace Hestia.Mediator.Infrastructure.Messaging;
+
+public interface IRequest { }
+
+public interface IRequest { }
+
+public interface IRequestHandler
+ where TRequest : IRequest
+{
+ Task Handle(TRequest request, CancellationToken cancellationToken);
+}
diff --git a/Hestia.Mediator/Infrastructure/Pipeline/IPipelineBehavior.cs b/Hestia.Mediator/Infrastructure/Pipeline/IPipelineBehavior.cs
new file mode 100644
index 0000000..56f29f6
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/Pipeline/IPipelineBehavior.cs
@@ -0,0 +1,12 @@
+namespace Hestia.Mediator.Infrastructure.Pipeline;
+
+public delegate Task RequestHandlerDelegate();
+
+public interface IPipelineBehavior
+ where TRequest : Messaging.IRequest
+{
+ Task Handle(
+ TRequest request,
+ RequestHandlerDelegate next,
+ CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/Hestia.Mediator/Infrastructure/Types/Unit.cs b/Hestia.Mediator/Infrastructure/Types/Unit.cs
new file mode 100644
index 0000000..945cb68
--- /dev/null
+++ b/Hestia.Mediator/Infrastructure/Types/Unit.cs
@@ -0,0 +1,6 @@
+namespace Hestia.Mediator.Infrastructure.Types;
+
+public readonly struct Unit
+{
+ public static readonly Unit Value = new();
+}
\ No newline at end of file
diff --git a/Hestia.Mediator/Services/MediatorService.cs b/Hestia.Mediator/Services/MediatorService.cs
new file mode 100644
index 0000000..69fdb1e
--- /dev/null
+++ b/Hestia.Mediator/Services/MediatorService.cs
@@ -0,0 +1,55 @@
+using Hestia.Mediator.Infrastructure;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Types;
+using System.Reflection;
+
+namespace Hestia.Mediator.Services;
+
+public class MediatorService(IServiceProvider serviceProvider) : IMediator
+{
+ public async Task Send(IRequest request, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ var handlerType = typeof(IRequestHandler<,>).MakeGenericType(request.GetType(), typeof(TResponse));
+
+ object? handler = serviceProvider.GetService(handlerType) ??
+ throw new InvalidOperationException($"No handler registered for {request.GetType().Name} -> {typeof(TResponse).Name}");
+
+ var method = handlerType.GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public) ??
+ throw new InvalidOperationException($"Handler {handlerType.Name} does not have a public Handle method");
+
+ try
+ {
+ object? result = method.Invoke(handler, [request, cancellationToken]);
+ return await (Task)result!;
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw ex.InnerException ?? ex;
+ }
+ }
+
+ public async Task Send(IRequest request, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ var handlerType = typeof(IRequestHandler<,>).MakeGenericType(request.GetType(), typeof(Unit));
+
+ object? handler = serviceProvider.GetService(handlerType) ??
+ throw new InvalidOperationException($"No handler registered for {request.GetType().Name} -> {nameof(Unit)}");
+
+ var method = handlerType.GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public) ??
+ throw new InvalidOperationException($"Handler {handlerType.Name} does not have a public Handle method");
+
+ try
+ {
+ object? result = method.Invoke(handler, [request, cancellationToken]);
+ await (Task)result!;
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw ex.InnerException ?? ex;
+ }
+ }
+}
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandlerTests.cs
index e9954c3..5ae7a3d 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandlerTests.cs
@@ -1,37 +1,26 @@
using Hestia.Access.Requests.Product.Commands.CreateProduct;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Commands.CreateProduct;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Commands.CreateProduct;
-public class CreateProductCommandHandlerTests : IDisposable
+public class CreateProductCommandHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly CreateProductCommandHandler _handler;
public CreateProductCommandHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new CreateProductCommandHandler(_context, _mockLogger.Object);
+ _handler = new CreateProductCommandHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldAddProductToDatabase_WhenCalled()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -44,23 +33,11 @@ public async Task Handle_ShouldAddProductToDatabase_WhenCalled()
};
var command = new CreateProductCommand(product);
-
- // Act
bool result = await _handler.Handle(command, CancellationToken.None);
- // Assert
Assert.True(result);
- var savedProduct = await _context.Product.FindAsync(product.Id);
+ var savedProduct = await Context.Product.FindAsync(product.Id);
Assert.NotNull(savedProduct);
- Assert.Equal(product.Name, savedProduct.Name);
- Assert.Equal(product.Description, savedProduct.Description);
- Assert.Equal(product.Price, savedProduct.Price);
- Assert.Equal(product.ExternalId, savedProduct.ExternalId);
- }
-
- public void Dispose()
- {
- _context.Dispose();
}
}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandlerTests.cs
index 39b3eb4..cf29ae5 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Commands.DeleteProduct;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Commands.DeleteProduct;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Commands.DeleteProduct;
-public class DeleteProductCommandHandlerTests : IDisposable
+public class DeleteProductCommandHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly DeleteProductCommandHandler _handler;
public DeleteProductCommandHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new DeleteProductCommandHandler(_context, _mockLogger.Object);
+ _handler = new DeleteProductCommandHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldRemoveProductFromDatabase_WhenCalled()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,23 +31,15 @@ public async Task Handle_ShouldRemoveProductFromDatabase_WhenCalled()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
var command = new DeleteProductCommand(product);
-
- // Act
bool result = await _handler.Handle(command, CancellationToken.None);
- // Assert
Assert.True(result);
- var deletedProduct = await _context.Product.FindAsync(product.Id);
- Assert.Null(deletedProduct); // Ensure the product is deleted
- }
-
- public void Dispose()
- {
- _context.Dispose();
+ var deletedProduct = await Context.Product.FindAsync(product.Id);
+ Assert.Null(deletedProduct);
}
-}
\ No newline at end of file
+}
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandlerTests.cs
index 98d94e3..f3470fd 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Commands.UpdateProduct;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Commands.UpdateProduct;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Commands.UpdateProduct;
-public class UpdateProductCommandHandlerTests : IDisposable
+public class UpdateProductCommandHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly UpdateProductCommandHandler _handler;
public UpdateProductCommandHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new UpdateProductCommandHandler(_context, _mockLogger.Object);
+ _handler = new UpdateProductCommandHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldUpdateProductInDatabase_WhenCalled()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,32 +31,23 @@ public async Task Handle_ShouldUpdateProductInDatabase_WhenCalled()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
- // Update product details
product.Name = "Updated Product";
product.Description = "Updated Description";
product.Price = 79.99m;
var command = new UpdateProductCommand(product);
-
- // Act
bool result = await _handler.Handle(command, CancellationToken.None);
- // Assert
Assert.True(result);
- var updatedProduct = await _context.Product.FindAsync(product.Id);
+ var updatedProduct = await Context.Product.FindAsync(product.Id);
Assert.NotNull(updatedProduct);
Assert.Equal(product.Name, updatedProduct.Name);
Assert.Equal(product.Description, updatedProduct.Description);
Assert.Equal(product.Price, updatedProduct.Price);
Assert.Equal(product.ExternalId, updatedProduct.ExternalId);
}
-
- public void Dispose()
- {
- _context.Dispose();
- }
}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandlerTests.cs
index 28ce037..c5da369 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Queries.GetExisting;
-public class GetExistingProductByCompositeIdQueryHandlerTests : IDisposable
+public class GetExistingProductByCompositeIdQueryHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly GetExistingProductByCompositeIdQueryHandler _handler;
public GetExistingProductByCompositeIdQueryHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new GetExistingProductByCompositeIdQueryHandler(_context, _mockLogger.Object);
+ _handler = new GetExistingProductByCompositeIdQueryHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldReturnProduct_WhenProductExists()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,15 +31,12 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
var query = new GetExistingProductByCompositeIdQuery(product.Id, product.ExternalId);
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.NotNull(result);
Assert.Equal(product.Id, result?.Id);
Assert.Equal(product.ExternalId, result?.ExternalId);
@@ -59,18 +45,9 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
[Fact]
public async Task Handle_ShouldReturnNull_WhenProductDoesNotExist()
{
- // Arrange
var query = new GetExistingProductByCompositeIdQuery(Guid.NewGuid(), "nonexistent-external-id");
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.Null(result);
}
-
- public void Dispose()
- {
- _context.Dispose();
- }
-}
+}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandlerTests.cs
index 0371f3a..06157d8 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Queries.GetExisting;
-public class GetExistingProductByExternalIdQueryHandlerTests : IDisposable
+public class GetExistingProductByExternalIdQueryHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly GetExistingProductByExternalIdQueryHandler _handler;
public GetExistingProductByExternalIdQueryHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new GetExistingProductByExternalIdQueryHandler(_context, _mockLogger.Object);
+ _handler = new GetExistingProductByExternalIdQueryHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldReturnProduct_WhenProductExists()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,15 +31,12 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
var query = new GetExistingProductByExternalIdQuery(product.ExternalId);
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.NotNull(result);
Assert.Equal(product.ExternalId, result?.ExternalId);
}
@@ -58,18 +44,9 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
[Fact]
public async Task Handle_ShouldReturnNull_WhenProductDoesNotExist()
{
- // Arrange
var query = new GetExistingProductByExternalIdQuery("nonexistent-external-id");
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.Null(result);
}
-
- public void Dispose()
- {
- _context.Dispose();
- }
}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandlerTests.cs
index cf83ebc..d1d862b 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Queries.GetExisting;
-public class GetExistingProductByIdQueryHandlerTests : IDisposable
+public class GetExistingProductByIdQueryHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly GetExistingProductByIdQueryHandler _handler;
public GetExistingProductByIdQueryHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new GetExistingProductByIdQueryHandler(_context, _mockLogger.Object);
+ _handler = new GetExistingProductByIdQueryHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldReturnProduct_WhenProductExists()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,15 +31,12 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
var query = new GetExistingProductByIdQuery(product.Id);
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.NotNull(result);
Assert.Equal(product.Id, result?.Id);
}
@@ -58,18 +44,9 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
[Fact]
public async Task Handle_ShouldReturnNull_WhenProductDoesNotExist()
{
- // Arrange
var query = new GetExistingProductByIdQuery(Guid.NewGuid());
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.Null(result);
}
-
- public void Dispose()
- {
- _context.Dispose();
- }
-}
+}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandlerTests.cs b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandlerTests.cs
index 2ad74f1..33f5081 100644
--- a/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandlerTests.cs
+++ b/Hestia.Persistence.Tests/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandlerTests.cs
@@ -1,36 +1,25 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
-using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using Microsoft.EntityFrameworkCore;
+using Hestia.Persistence.Tests.Shared;
using Microsoft.Extensions.Logging;
using Moq;
namespace Hestia.Persistence.Tests.Handlers.Product.Queries.GetExisting;
-public class GetExistingProductByUserQueryHandlerTests : IDisposable
+public class GetExistingProductByUserQueryHandlerTests : RheaContextTestBase
{
- private readonly RheaContext _context;
private readonly Mock> _mockLogger;
private readonly GetExistingProductByUserQueryHandler _handler;
public GetExistingProductByUserQueryHandlerTests()
{
- var dbContextOptions = new DbContextOptionsBuilder()
- .UseSqlite("DataSource=:memory:")
- .Options;
-
- _context = new RheaContext(dbContextOptions);
- _context.Database.OpenConnection();
- _context.Database.EnsureCreated();
-
_mockLogger = new Mock>();
- _handler = new GetExistingProductByUserQueryHandler(_context, _mockLogger.Object);
+ _handler = new GetExistingProductByUserQueryHandler(Context, _mockLogger.Object);
}
[Fact]
public async Task Handle_ShouldReturnProduct_WhenProductExists()
{
- // Arrange
var product = new Access.Entities.Product.Product(Guid.NewGuid())
{
Name = "Test Product",
@@ -42,15 +31,12 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
DateEdited = DateTime.UtcNow
};
- await _context.Product.AddAsync(product);
- await _context.SaveChangesAsync();
+ await Context.Product.AddAsync(product);
+ await Context.SaveChangesAsync();
var query = new GetExistingProductByUserQuery(product.UserId, product.ExternalId);
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.NotNull(result);
Assert.Equal(product.UserId, result?.UserId);
Assert.Equal(product.ExternalId, result?.ExternalId);
@@ -59,18 +45,9 @@ public async Task Handle_ShouldReturnProduct_WhenProductExists()
[Fact]
public async Task Handle_ShouldReturnNull_WhenProductDoesNotExist()
{
- // Arrange
var query = new GetExistingProductByUserQuery("nonexistent-user-id", "nonexistent-external-id");
-
- // Act
var result = await _handler.Handle(query, CancellationToken.None);
- // Assert
Assert.Null(result);
}
-
- public void Dispose()
- {
- _context.Dispose();
- }
}
\ No newline at end of file
diff --git a/Hestia.Persistence.Tests/Hestia.Persistence.Tests.csproj b/Hestia.Persistence.Tests/Hestia.Persistence.Tests.csproj
index 53106a9..61aec92 100644
--- a/Hestia.Persistence.Tests/Hestia.Persistence.Tests.csproj
+++ b/Hestia.Persistence.Tests/Hestia.Persistence.Tests.csproj
@@ -8,12 +8,18 @@
-
-
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Hestia.Persistence.Tests/Shared/RheaContextTestBase.cs b/Hestia.Persistence.Tests/Shared/RheaContextTestBase.cs
new file mode 100644
index 0000000..185da80
--- /dev/null
+++ b/Hestia.Persistence.Tests/Shared/RheaContextTestBase.cs
@@ -0,0 +1,22 @@
+using Hestia.Persistence.Contexts;
+using Microsoft.EntityFrameworkCore;
+
+namespace Hestia.Persistence.Tests.Shared;
+
+public abstract class RheaContextTestBase : IDisposable
+{
+ protected readonly RheaContext Context;
+
+ protected RheaContextTestBase()
+ {
+ var dbContextOptions = new DbContextOptionsBuilder()
+ .UseSqlite("DataSource=:memory:")
+ .Options;
+
+ Context = new RheaContext(dbContextOptions);
+ Context.Database.OpenConnection();
+ Context.Database.EnsureCreated();
+ }
+
+ public void Dispose() => Context.Dispose();
+}
\ No newline at end of file
diff --git a/Hestia.Persistence/Contexts/HestiaContext.cs b/Hestia.Persistence/Contexts/HestiaContext.cs
index 884f9b0..98d489a 100644
--- a/Hestia.Persistence/Contexts/HestiaContext.cs
+++ b/Hestia.Persistence/Contexts/HestiaContext.cs
@@ -3,38 +3,16 @@
using Hestia.Domain.Models.Authentication;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Reflection;
namespace Hestia.Persistence.Contexts;
-public class HestiaContext : IdentityUserContext
+public class HestiaContext(DbContextOptions options) : IdentityUserContext(options)
{
- private readonly IConfiguration configuration;
-
public DbSet TokenLog { get; set; } = null!;
public DbSet User { get; set; } = null!;
- public HestiaContext()
- {
- }
-
- public HestiaContext(IConfiguration configuration) => this.configuration = configuration;
-
- public HestiaContext(DbContextOptions options)
- : base(options)
- {
- }
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- if (optionsBuilder.IsConfigured)
- return;
-
- optionsBuilder.UseNpgsql(configuration.GetConnectionString("AuthServer"));
- }
-
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
@@ -43,20 +21,18 @@ protected override void OnModelCreating(ModelBuilder builder)
public async Task ExecuteInTransactionAsync(Func> action, ILogger logger)
{
- using (var transaction = await Database.BeginTransactionAsync())
+ using var transaction = await Database.BeginTransactionAsync();
+ try
+ {
+ var result = await action(this);
+ await transaction.CommitAsync();
+ return result;
+ }
+ catch (Exception ex)
{
- try
- {
- var result = await action(this);
- await transaction.CommitAsync();
- return result;
- }
- catch (Exception ex)
- {
- await transaction.RollbackAsync();
- logger.LogCritical(ex, "An error occurred while executing the database action: {Message} | Context: {Context}", ex.Message, typeof(T).Name);
- throw;
- }
+ await transaction.RollbackAsync();
+ logger.LogCritical(ex, "An error occurred while executing the database action: {Message} | Context: {Context}", ex.Message, typeof(T).Name);
+ throw;
}
}
}
\ No newline at end of file
diff --git a/Hestia.Persistence/Contexts/RheaContext.cs b/Hestia.Persistence/Contexts/RheaContext.cs
index ab18cfc..095d544 100644
--- a/Hestia.Persistence/Contexts/RheaContext.cs
+++ b/Hestia.Persistence/Contexts/RheaContext.cs
@@ -1,57 +1,36 @@
using Hestia.Access.Entities.Product;
using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Reflection;
namespace Hestia.Persistence.Contexts;
-public class RheaContext : DbContext
+public class RheaContext(DbContextOptions options) : DbContext(options)
{
- private readonly IConfiguration configuration;
public DbSet Product { get; set; } = null!;
- public RheaContext()
- {
- }
-
- public RheaContext(IConfiguration configuration) => this.configuration = configuration;
-
- public RheaContext(DbContextOptions options)
- : base(options)
- {
- }
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- if (optionsBuilder.IsConfigured)
- return;
-
- optionsBuilder.UseNpgsql(configuration.GetConnectionString("DataServer"));
- }
-
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
- public async Task ExecuteInTransactionAsync(Func> action, ILogger logger)
+ public async Task ExecuteInTransactionAsync(
+ Func> action,
+ ILogger logger)
{
- using (var transaction = await Database.BeginTransactionAsync())
+ using var transaction = await Database.BeginTransactionAsync();
+ try
+ {
+ var result = await action(this);
+ await transaction.CommitAsync();
+ return result;
+ }
+ catch (Exception ex)
{
- try
- {
- var result = await action(this);
- await transaction.CommitAsync();
- return result;
- }
- catch (Exception ex)
- {
- await transaction.RollbackAsync();
- logger.LogCritical(ex, "An error occurred while executing the database action: {Message} | Context: {Context}", ex.Message, typeof(T).Name);
- throw;
- }
+ await transaction.RollbackAsync();
+ logger.LogCritical(ex, "An error occurred while executing the database action: {Message} | Context: {Context}", ex.Message, typeof(T).Name);
+ throw;
}
}
}
\ No newline at end of file
diff --git a/Hestia.Persistence/Handlers/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommandHandler.cs b/Hestia.Persistence/Handlers/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommandHandler.cs
index a0a6711..9a316e6 100644
--- a/Hestia.Persistence/Handlers/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/Authentication/Commands/CreateTokenLog/CreateOrUpdateTokenLogCommandHandler.cs
@@ -1,7 +1,8 @@
using Hestia.Access.Entities.Authentication;
using Hestia.Access.Requests.Authentication.Commands.CreateTokenLog;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Types;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs b/Hestia.Persistence/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
index 1469424..e1e68f4 100644
--- a/Hestia.Persistence/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Commands/CreateProduct/CreateProductCommandHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Access.Requests.Product.Commands.CreateProduct;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
using Hestia.Persistence.Handlers.Product.Queries.GetExisting;
-using MediatR;
using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.Product.Commands.CreateProduct;
diff --git a/Hestia.Persistence/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs b/Hestia.Persistence/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
index 588335c..77846a5 100644
--- a/Hestia.Persistence/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Commands/DeleteProduct/DeleteProductCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Commands.DeleteProduct;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.Product.Commands.DeleteProduct;
diff --git a/Hestia.Persistence/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs b/Hestia.Persistence/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
index f6c07cd..3365d70 100644
--- a/Hestia.Persistence/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Commands/UpdateProduct/UpdateProductCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Commands.UpdateProduct;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.Product.Commands.UpdateProduct;
diff --git a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandler.cs b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandler.cs
index b2448ae..3df330c 100644
--- a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByCompositeIdQueryHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandler.cs b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandler.cs
index 11c1609..e325a79 100644
--- a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByExternalIdQueryHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandler.cs b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandler.cs
index 618533e..11170d1 100644
--- a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByIdQueryHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandler.cs b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandler.cs
index fdf58a5..4434574 100644
--- a/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/Product/Queries/GetExisting/GetExistingProductByUserQueryHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.Product.Queries.GetExisting;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/Shared/ExecuteSaveChangesAsyncHandler.cs b/Hestia.Persistence/Handlers/Shared/ExecuteSaveChangesAsyncHandler.cs
index 2397a61..c6f9dae 100644
--- a/Hestia.Persistence/Handlers/Shared/ExecuteSaveChangesAsyncHandler.cs
+++ b/Hestia.Persistence/Handlers/Shared/ExecuteSaveChangesAsyncHandler.cs
@@ -1,6 +1,7 @@
using Hestia.Access.Requests.Shared;
+using Hestia.Mediator.Infrastructure.Messaging;
+using Hestia.Mediator.Infrastructure.Types;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.Shared;
diff --git a/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateApplicationUserCommandHandler.cs b/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateApplicationUserCommandHandler.cs
index ff05e5b..ac955ef 100644
--- a/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateApplicationUserCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateApplicationUserCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.User.Commands.CreateUser;
using Hestia.Domain.Models.Authentication;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using Microsoft.AspNetCore.Identity;
namespace Hestia.Persistence.Handlers.User.Commands.CreateUser;
diff --git a/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateInternalUserCommandHandler.cs b/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateInternalUserCommandHandler.cs
index 9db92a1..6a94631 100644
--- a/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateInternalUserCommandHandler.cs
+++ b/Hestia.Persistence/Handlers/User/Commands/CreateUser/CreateInternalUserCommandHandler.cs
@@ -1,6 +1,6 @@
using Hestia.Access.Requests.User.Commands.CreateUser;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.User.Commands.CreateUser;
diff --git a/Hestia.Persistence/Handlers/User/Queries/UserExists/GetExistingUserQueryHandler.cs b/Hestia.Persistence/Handlers/User/Queries/UserExists/GetExistingUserQueryHandler.cs
index 65da54a..7d7c669 100644
--- a/Hestia.Persistence/Handlers/User/Queries/UserExists/GetExistingUserQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/User/Queries/UserExists/GetExistingUserQueryHandler.cs
@@ -1,7 +1,7 @@
using Hestia.Access.Requests.User.Queries.UserExists;
using Hestia.Domain.Models.Authentication;
+using Hestia.Mediator.Infrastructure.Messaging;
using Hestia.Persistence.Contexts;
-using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
diff --git a/Hestia.Persistence/Handlers/User/Queries/ValidateUserLogin/ValidateUserLoginQueryHandler.cs b/Hestia.Persistence/Handlers/User/Queries/ValidateUserLogin/ValidateUserLoginQueryHandler.cs
index 0ecc3a7..c94910f 100644
--- a/Hestia.Persistence/Handlers/User/Queries/ValidateUserLogin/ValidateUserLoginQueryHandler.cs
+++ b/Hestia.Persistence/Handlers/User/Queries/ValidateUserLogin/ValidateUserLoginQueryHandler.cs
@@ -1,13 +1,11 @@
using Hestia.Access.Requests.User.Queries.ValidateUserLogin;
using Hestia.Domain.Models.Authentication;
-using Hestia.Persistence.Contexts;
-using MediatR;
+using Hestia.Mediator.Infrastructure.Messaging;
using Microsoft.AspNetCore.Identity;
-using Microsoft.Extensions.Logging;
namespace Hestia.Persistence.Handlers.User.Queries.ValidateUserLogin;
-internal class ValidateUserLoginQueryHandler(HestiaContext context, UserManager userManager, ILogger logger) : IRequestHandler
+internal class ValidateUserLoginQueryHandler(UserManager userManager) : IRequestHandler
{
public async Task Handle(ValidateUserLoginQuery request, CancellationToken cancellationToken) =>
await userManager.CheckPasswordAsync(request.User, request.LoginPassword!);
diff --git a/Hestia.Persistence/Hestia.Persistence.csproj b/Hestia.Persistence/Hestia.Persistence.csproj
index 9047287..dd9c539 100644
--- a/Hestia.Persistence/Hestia.Persistence.csproj
+++ b/Hestia.Persistence/Hestia.Persistence.csproj
@@ -7,20 +7,19 @@
-
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/Hestia.sln b/Hestia.sln
index a9465ef..d44559a 100644
--- a/Hestia.sln
+++ b/Hestia.sln
@@ -36,6 +36,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hestia.Application.Tests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hestia.Persistence.Tests", "Hestia.Persistence.Tests\Hestia.Persistence.Tests.csproj", "{7D1330E9-A979-4450-A5DC-F649AE76997C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hestia.Mediator", "Hestia.Mediator\Hestia.Mediator.csproj", "{0AD8CF15-88C7-4578-B28D-411906F37BA3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hestia.Mapper", "Hestia.Mapper\Hestia.Mapper.csproj", "{C0C93A3B-328E-4D7F-8CE9-2323FC80DF42}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hestia.Application.Models", "Hestia.Application.Models\Hestia.Application.Models.csproj", "{F1504DC2-B9B0-4541-A444-1ACEF29736F3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -78,6 +84,18 @@ Global
{7D1330E9-A979-4450-A5DC-F649AE76997C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D1330E9-A979-4450-A5DC-F649AE76997C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D1330E9-A979-4450-A5DC-F649AE76997C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0AD8CF15-88C7-4578-B28D-411906F37BA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0AD8CF15-88C7-4578-B28D-411906F37BA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0AD8CF15-88C7-4578-B28D-411906F37BA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0AD8CF15-88C7-4578-B28D-411906F37BA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C0C93A3B-328E-4D7F-8CE9-2323FC80DF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C0C93A3B-328E-4D7F-8CE9-2323FC80DF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C0C93A3B-328E-4D7F-8CE9-2323FC80DF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C0C93A3B-328E-4D7F-8CE9-2323FC80DF42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1504DC2-B9B0-4541-A444-1ACEF29736F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1504DC2-B9B0-4541-A444-1ACEF29736F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1504DC2-B9B0-4541-A444-1ACEF29736F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F1504DC2-B9B0-4541-A444-1ACEF29736F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -92,6 +110,9 @@ Global
{8C67DC6A-C409-4807-A0F9-050CA6241620} = {75F92E7E-EAF5-430E-B7F1-11ACAE8C6D1E}
{09840348-019A-44D7-9484-578704D8C579} = {75F92E7E-EAF5-430E-B7F1-11ACAE8C6D1E}
{7D1330E9-A979-4450-A5DC-F649AE76997C} = {75F92E7E-EAF5-430E-B7F1-11ACAE8C6D1E}
+ {0AD8CF15-88C7-4578-B28D-411906F37BA3} = {11A9C530-E38E-468E-B5B7-75C80BEDED80}
+ {C0C93A3B-328E-4D7F-8CE9-2323FC80DF42} = {35AEA3B0-22A3-4D12-9075-8EA4BE16DA29}
+ {F1504DC2-B9B0-4541-A444-1ACEF29736F3} = {35AEA3B0-22A3-4D12-9075-8EA4BE16DA29}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {741C93FA-CBE6-4E96-A62E-040CFD186E3C}
diff --git a/README.md b/README.md
index 688de65..768e0d7 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ This project has the following structure:
- Implementation of [**Clean architecture**](https://www.geeksforgeeks.org/complete-guide-to-clean-architecture/) and [**SOLID**](https://en.wikipedia.org/wiki/SOLID) software design principles
- [**.NET 9**](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) with [**Entity Framework Core**](https://learn.microsoft.com/en-us/ef/core/)
-- [**Command Query Responsibility Segregation (CQRS)**](https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs) with [**MediatR pattern**](https://en.wikipedia.org/wiki/Mediator_pattern)
+- [**Command Query Responsibility Segregation (CQRS)**](https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs) with [**Mediator pattern**](https://en.wikipedia.org/wiki/Mediator_pattern)
- [**JWT Token & Authentication**](https://en.wikipedia.org/wiki/JSON_Web_Token) with [**ASP.NET Core Identity**](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-9.0&tabs=visual-studio)
- Global exception middleware handling and data validation using [**Fluent Validation**](https://docs.fluentvalidation.net/en/latest/) library
- Standardized API response modeling