new event queue adding, register endpoint finished

This commit is contained in:
2026-01-19 03:15:01 +01:00
Unverified
parent 44eb5801fa
commit a01e8666a3
9 changed files with 54 additions and 55 deletions

View File

@@ -0,0 +1,6 @@
namespace TimetableDesigner.Backend.Services.Authentication.DTO.Events;
public record RegisterEvent(
long Id,
string Email
);

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,5 @@
<Solution> <Solution>
<Project Path="TimetableDesigner.Backend.Services.Authentication.DTO.Events/TimetableDesigner.Backend.Services.Authentication.DTO.Events.csproj" />
<Project Path="TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI/TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.csproj" /> <Project Path="TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI/TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.csproj" />
<Project Path="TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj" /> <Project Path="TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj" />
</Solution> </Solution>

View File

@@ -1,7 +1,9 @@
using MediatR; using MediatR;
using TimetableDesigner.Backend.Events;
using TimetableDesigner.Backend.Services.Authentication.Application.Helpers; using TimetableDesigner.Backend.Services.Authentication.Application.Helpers;
using TimetableDesigner.Backend.Services.Authentication.Database; using TimetableDesigner.Backend.Services.Authentication.Database;
using TimetableDesigner.Backend.Services.Authentication.Database.Model; using TimetableDesigner.Backend.Services.Authentication.Database.Model;
using TimetableDesigner.Backend.Services.Authentication.DTO.Events;
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
@@ -9,11 +11,13 @@ public class RegisterHandler : IRequestHandler<RegisterCommand, RegisterResult>
{ {
private readonly DatabaseContext _databaseContext; private readonly DatabaseContext _databaseContext;
private readonly IPasswordHasher _passwordHasher; private readonly IPasswordHasher _passwordHasher;
private readonly IEventQueuePublisher _eventQueuePublisher;
public RegisterHandler(DatabaseContext databaseContext, IPasswordHasher passwordHasher) public RegisterHandler(DatabaseContext databaseContext, IPasswordHasher passwordHasher, IEventQueuePublisher eventQueuePublisher)
{ {
_databaseContext = databaseContext; _databaseContext = databaseContext;
_passwordHasher = passwordHasher; _passwordHasher = passwordHasher;
_eventQueuePublisher = eventQueuePublisher;
} }
public async Task<RegisterResult> Handle(RegisterCommand command, CancellationToken cancellationToken) public async Task<RegisterResult> Handle(RegisterCommand command, CancellationToken cancellationToken)
@@ -29,7 +33,8 @@ public class RegisterHandler : IRequestHandler<RegisterCommand, RegisterResult>
await _databaseContext.Accounts.AddAsync(account, cancellationToken); await _databaseContext.Accounts.AddAsync(account, cancellationToken);
await _databaseContext.SaveChangesAsync(cancellationToken); await _databaseContext.SaveChangesAsync(cancellationToken);
// Publish event (probably in transaction) RegisterEvent eventData = account.ToEvent();
await _eventQueuePublisher.PublishAsync(eventData);
RegisterResult result = account.ToResult(); RegisterResult result = account.ToResult();
return result; return result;

View File

@@ -1,4 +1,5 @@
using TimetableDesigner.Backend.Services.Authentication.Database.Model; using TimetableDesigner.Backend.Services.Authentication.Database.Model;
using TimetableDesigner.Backend.Services.Authentication.DTO.Events;
using TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI; using TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI;
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
@@ -13,4 +14,7 @@ public static class RegisterMappers
public static RegisterResponse ToResponse(this RegisterResult result) => public static RegisterResponse ToResponse(this RegisterResult result) =>
new RegisterResponse(result.Id, result.Email); new RegisterResponse(result.Id, result.Email);
public static RegisterEvent ToEvent(this Account account) =>
new RegisterEvent(account.Id, account.Email);
} }

View File

@@ -17,14 +17,19 @@ public static class Program
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
WebApplication app = WebApplication.CreateBuilder(args) WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
.SetupOpenApi()
.SetupSecurity() string databaseConnectionString = builder.Configuration.GetConnectionString("Database")!;
.SetupDatabase() string eventQueueConnectionString = builder.Configuration.GetConnectionString("EventQueue")!;
.SetupHelpers()
.SetupValidation() builder.Services.AddOpenApi();
.SetupMediatR() builder.Services.AddDbContext<DatabaseContext>(x => x.UseNpgsql(databaseConnectionString), ServiceLifetime.Transient);
.Build(); builder.Services.AddEventQueue<RabbitMQEventQueue>(eventQueueConnectionString);
builder.Services.AddHelpers();
builder.Services.AddValidators();
builder.Services.AddMediatR(x => x.RegisterServicesFromAssembly(typeof(Program).Assembly));
WebApplication app = builder.Build();
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
app.MapOpenApi(); app.MapOpenApi();
@@ -36,49 +41,16 @@ public static class Program
app.Run(); app.Run();
} }
private static WebApplicationBuilder SetupOpenApi(this WebApplicationBuilder builder) private static IServiceCollection AddHelpers(this IServiceCollection services)
{ {
builder.Services.AddEventQueue<RabbitMQEventQueue>(cfg => services.AddSingleton<IPasswordHasher, PasswordHasher>();
{ return services;
cfg.Hostname = "localhost";
cfg.Port = 5672;
cfg.Username = "user";
cfg.Password = "l4JxOIuSoyod86N";
cfg.ExchangeName = "events";
cfg.QueuePrefix = "authentication";
});
builder.Services.AddOpenApi();
return builder;
} }
private static WebApplicationBuilder SetupSecurity(this WebApplicationBuilder builder) private static IServiceCollection AddValidators(this IServiceCollection services)
{ {
//builder.Services.AddAuthorization(); services.AddScoped<IValidator<TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.RegisterRequest>, RegisterRequestValidator>();
return builder; return services;
}
private static WebApplicationBuilder SetupDatabase(this WebApplicationBuilder builder)
{
builder.Services.AddDbContext<DatabaseContext>(x => x.UseNpgsql(builder.Configuration.GetConnectionString("Database")), ServiceLifetime.Transient);
return builder;
}
private static WebApplicationBuilder SetupHelpers(this WebApplicationBuilder builder)
{
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
return builder;
}
private static WebApplicationBuilder SetupValidation(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IValidator<TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.RegisterRequest>, RegisterRequestValidator>();
return builder;
}
private static WebApplicationBuilder SetupMediatR(this WebApplicationBuilder builder)
{
builder.Services.AddMediatR(x => x.RegisterServicesFromAssembly(typeof(Program).Assembly));
return builder;
} }
private static WebApplication InitializeDatabase(this WebApplication app) private static WebApplication InitializeDatabase(this WebApplication app)

View File

@@ -18,11 +18,12 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<PackageReference Include="timetabledesigner.backend.events.extensions.aspnetcore.openapi" Version="1.0.0" /> <PackageReference Include="timetabledesigner.backend.events.extensions.aspnetcore.openapi" Version="1.0.1" />
<PackageReference Include="TimetableDesigner.Backend.Events.Providers.RabbitMQ" Version="1.0.1" /> <PackageReference Include="TimetableDesigner.Backend.Events.Providers.RabbitMQ" Version="1.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\TimetableDesigner.Backend.Services.Authentication.DTO.Events\TimetableDesigner.Backend.Services.Authentication.DTO.Events.csproj" />
<ProjectReference Include="..\TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI\TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.csproj" /> <ProjectReference Include="..\TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI\TimetableDesigner.Backend.Services.Authentication.DTO.WebAPI.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -29,7 +29,7 @@ public static class Endpoints
return app; return app;
} }
private static async Task<Results<Created<RegisterResponse>, ValidationProblem>> Register(IMediator mediator, IValidator<RegisterRequest> validator, RegisterRequest request) private static async Task<Results<Created<RegisterResponse>, ValidationProblem>> Register(IMediator mediator, IValidator<RegisterRequest> validator, RegisterRequest request, CancellationToken cancellationToken)
{ {
ValidationResult validationResult = await validator.ValidateAsync(request); ValidationResult validationResult = await validator.ValidateAsync(request);
if (!validationResult.IsValid) if (!validationResult.IsValid)
@@ -38,7 +38,7 @@ public static class Endpoints
} }
RegisterCommand registerCommand = request.ToCommand(); RegisterCommand registerCommand = request.ToCommand();
RegisterResult result = await mediator.Send(registerCommand); RegisterResult result = await mediator.Send(registerCommand, cancellationToken);
RegisterResponse response = result.ToResponse(); RegisterResponse response = result.ToResponse();
return TypedResults.Created($"accounts/{response.Id}", response); return TypedResults.Created($"accounts/{response.Id}", response);

View File

@@ -7,6 +7,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"Database": "Host=localhost;Port=5433;Database=ttd_authentication;Username=postgres;Password=l4JxOIuSoyod86N;Include Error Detail=True" "Database": "Host=localhost;Port=5433;Database=ttd_authentication;Username=postgres;Password=l4JxOIuSoyod86N;Include Error Detail=True",
"EventQueue": "Hostname=localhost;Port=5672;Username=user;Password=l4JxOIuSoyod86N;ExchangeName=events;QueuePrefix=authentication"
} }
} }