diff --git a/scripts/keycloak/realm-export.json b/scripts/keycloak/realm-export.json index 7a8102d..45d22fe 100644 --- a/scripts/keycloak/realm-export.json +++ b/scripts/keycloak/realm-export.json @@ -47,6 +47,42 @@ "quickLoginCheckMilliSeconds": 1000, "maxDeltaTimeSeconds": 43200, "failureFactor": 30, + "users": [ + { + "username": "AdminUser", + "enabled": true, + "emailVerified": true, + "firstName": "admin", + "lastName": "user", + "email": "admin@mail.com", + "credentials": [ + { + "type": "password", + "value": "password" + } + ], + "groups": [ + "Admin" + ] + }, + { + "username": "StandardUser", + "enabled": true, + "emailVerified": true, + "firstName": "Standard", + "lastName": "User", + "email": "standard@mail.com", + "credentials": [ + { + "type": "password", + "value": "password" + } + ], + "groups": [ + "Standard" + ] + } + ], "roles": { "realm": [ { @@ -768,7 +804,8 @@ "phone", "offline_access", "organization", - "microprofile-jwt" + "microprofile-jwt", + "minimal-api-aud" ] }, { diff --git a/src/MinimalApiTemplate.Api/Configurations/Swagger.cs b/src/MinimalApiTemplate.Api/Configurations/Swagger.cs index 91873d2..7b6ed64 100644 --- a/src/MinimalApiTemplate.Api/Configurations/Swagger.cs +++ b/src/MinimalApiTemplate.Api/Configurations/Swagger.cs @@ -24,8 +24,7 @@ public static void ConfigureSwagger(this IServiceCollection services, IConfigura TokenUrl = new Uri(config["AuthorityOptions:TokenUrl"]!), Scopes = new Dictionary { - { "openid", "OpenID scope" }, - { "profile", "Profile scope" } + { "minimal-api-aud", "Minimal Api" } } } } diff --git a/src/MinimalApiTemplate.Api/GlobalUsings.cs b/src/MinimalApiTemplate.Api/GlobalUsings.cs index d762342..a3310c9 100644 --- a/src/MinimalApiTemplate.Api/GlobalUsings.cs +++ b/src/MinimalApiTemplate.Api/GlobalUsings.cs @@ -1,6 +1,6 @@ global using System.Net; global using Riok.Mapperly.Abstractions; -global using MediatR; +global using Mediator; global using Microsoft.AspNetCore.Http.HttpResults; global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.OutputCaching; diff --git a/src/MinimalApiTemplate.Api/Properties/launchSettings.json b/src/MinimalApiTemplate.Api/Properties/launchSettings.json index 4512e19..d1121cb 100644 --- a/src/MinimalApiTemplate.Api/Properties/launchSettings.json +++ b/src/MinimalApiTemplate.Api/Properties/launchSettings.json @@ -6,7 +6,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "https://localhost:8000/swagger" + "applicationUrl": "https://localhost:8901/swagger" }, "IIS Express": { "commandName": "IISExpress", diff --git a/src/MinimalApiTemplate.Api/appsettings.json b/src/MinimalApiTemplate.Api/appsettings.json index 3c1c414..508225d 100644 --- a/src/MinimalApiTemplate.Api/appsettings.json +++ b/src/MinimalApiTemplate.Api/appsettings.json @@ -21,11 +21,11 @@ "AuthorityOptions": { "Authority": "http://localhost:8930/realms/my-realm", "AuthorizationUrl": "http://localhost:8930/realms/my-realm/protocol/openid-connect/auth", - "MetaDataUrl": "http://host.docker.internal:8930/realms/my-realm/.well-known/openid-configuration", - "TokenUrl": "http://host.docker.internal:8930/realms/my-realm/protocol/openid-connect/token", + "MetaDataUrl": "http://localhost:8930/realms/my-realm/.well-known/openid-configuration", + "TokenUrl": "http://localhost:8930/realms/my-realm/protocol/openid-connect/token", "Issuer": "http://localhost:8930/realms/my-realm", "Client": "minimal-api-client", - "Audience": "account" + "Audience": "minimal-api-client" }, "Serilog": { "Using": [ diff --git a/src/MinimalApiTemplate.AppHost/MinimalApiTemplate.AppHost.csproj b/src/MinimalApiTemplate.AppHost/MinimalApiTemplate.AppHost.csproj index 2130970..8f9d9b6 100644 --- a/src/MinimalApiTemplate.AppHost/MinimalApiTemplate.AppHost.csproj +++ b/src/MinimalApiTemplate.AppHost/MinimalApiTemplate.AppHost.csproj @@ -12,13 +12,14 @@ - - - - - - - + + + + + + + + diff --git a/src/MinimalApiTemplate.AppHost/Program.cs b/src/MinimalApiTemplate.AppHost/Program.cs index cebe08b..2b9832a 100644 --- a/src/MinimalApiTemplate.AppHost/Program.cs +++ b/src/MinimalApiTemplate.AppHost/Program.cs @@ -18,7 +18,12 @@ .WithLifetime(ContainerLifetime.Persistent) .WithManagementPlugin(8001); -builder.AddProject("minimalapitemplate-api") +var keycloak = builder.AddKeycloak("Keycloak", 8930) + .WithDataVolume() + .WithRealmImport("../../scripts/keycloak/") + .WithLifetime(ContainerLifetime.Persistent); + +builder.AddProject("minimalapitemplate-api") .WithReference(database) .WaitFor(database) .WithReference(rabbit) @@ -26,6 +31,8 @@ .WithReference(redis) .WaitFor(redis) .WaitFor(seq) + .WithReference(keycloak) + .WaitFor(keycloak) .WithEnvironment("MassTransit__PublishEnabled", "true") .WithEnvironment("SEQ_SERVER_URL", "http://localhost:8002"); diff --git a/src/MinimalApiTemplate.Application/Common/Behaviours/PerformanceBehaviour.cs b/src/MinimalApiTemplate.Application/Common/Behaviours/PerformanceBehaviour.cs index 9148cde..db1305c 100644 --- a/src/MinimalApiTemplate.Application/Common/Behaviours/PerformanceBehaviour.cs +++ b/src/MinimalApiTemplate.Application/Common/Behaviours/PerformanceBehaviour.cs @@ -1,36 +1,38 @@ using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using MinimalApiTemplate.Application.Common.Settings; namespace MinimalApiTemplate.Application.Common.Behaviours; public class PerformanceBehaviour : IPipelineBehavior - where TRequest : IRequest + where TRequest : IMessage { private readonly Stopwatch _timer; private readonly ILogger _logger; - private readonly ICurrentUserService _currentUserService; + private readonly IServiceScopeFactory _serviceScope; private readonly AppSettings _appSettings; public PerformanceBehaviour( #pragma warning disable S6672 // Generic logger injection should match enclosing type ILogger logger, #pragma warning restore S6672 // Generic logger injection should match enclosing type - ICurrentUserService currentUserService, + IServiceScopeFactory serviceScope, IOptions appSettings) { _timer = new Stopwatch(); _logger = logger; - _currentUserService = currentUserService; + _serviceScope = serviceScope; _appSettings = appSettings.Value; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async ValueTask Handle(TRequest message, CancellationToken cancellationToken, MessageHandlerDelegate next) { + _timer.Start(); - var response = await next(); + var response = await next(message, cancellationToken); _timer.Stop(); @@ -39,11 +41,15 @@ public async Task Handle(TRequest request, RequestHandlerDelegate= _appSettings.Logs.Performance.SlowRunningHandlerThreshold) { + using var scope = _serviceScope.CreateScope(); + var requestName = typeof(TRequest).Name; - var userId = _currentUserService.UserId ?? string.Empty; + + var currentUserService = scope.ServiceProvider.GetRequiredService(); + var userId = currentUserService.UserId ?? string.Empty; _logger.LogWarning("Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@Request}", - requestName, elapsedMilliseconds, userId, request); + requestName, elapsedMilliseconds, userId, message); } return response; diff --git a/src/MinimalApiTemplate.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs b/src/MinimalApiTemplate.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs index 333d218..4fa4651 100644 --- a/src/MinimalApiTemplate.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs +++ b/src/MinimalApiTemplate.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs @@ -1,7 +1,7 @@ namespace MinimalApiTemplate.Application.Common.Behaviours; public class UnhandledExceptionBehaviour : IPipelineBehavior - where TRequest : IRequest + where TRequest : IMessage { private readonly ILogger _logger; @@ -12,17 +12,17 @@ public UnhandledExceptionBehaviour(ILogger logger) _logger = logger; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async ValueTask Handle(TRequest message, CancellationToken cancellationToken, MessageHandlerDelegate next) { try { - return await next(); + return await next(message, cancellationToken); } catch (Exception ex) { var requestName = typeof(TRequest).Name; - _logger.LogError(ex, "Request: Unhandled Exception for Request {Name} {@Request}", requestName, request); + _logger.LogError(ex, "Request: Unhandled Exception for Request {Name} {@Request}", requestName, message); throw; } diff --git a/src/MinimalApiTemplate.Application/Common/Behaviours/ValidationBehaviour.cs b/src/MinimalApiTemplate.Application/Common/Behaviours/ValidationBehaviour.cs index bcb1460..10069ae 100644 --- a/src/MinimalApiTemplate.Application/Common/Behaviours/ValidationBehaviour.cs +++ b/src/MinimalApiTemplate.Application/Common/Behaviours/ValidationBehaviour.cs @@ -1,7 +1,7 @@ namespace MinimalApiTemplate.Application.Common.Behaviours; public class ValidationBehaviour : IPipelineBehavior - where TRequest : IRequest + where TRequest : IMessage { private readonly IEnumerable> _validators; @@ -10,11 +10,11 @@ public ValidationBehaviour(IEnumerable> validators) _validators = validators; } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async ValueTask Handle(TRequest message, CancellationToken cancellationToken, MessageHandlerDelegate next) { if (_validators.Any()) { - var context = new ValidationContext(request); + var context = new ValidationContext(message); var validationResults = await Task.WhenAll( _validators.Select(v => @@ -28,6 +28,6 @@ public async Task Handle(TRequest request, RequestHandlerDelegate + builder.Services.AddSingleton(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); + builder.Services.AddSingleton(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); + builder.Services.AddSingleton(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); + + builder.Services.AddMediator(options => { - options.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); - options.AddBehavior(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); - options.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); - options.AddBehavior(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); + options.ServiceLifetime = ServiceLifetime.Scoped; }); return builder; diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/CreateTodoItem/CreateTodoItemCommand.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/CreateTodoItem/CreateTodoItemCommand.cs index 26ffa13..109e599 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/CreateTodoItem/CreateTodoItemCommand.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/CreateTodoItem/CreateTodoItemCommand.cs @@ -22,7 +22,7 @@ public CreateTodoItemCommandHandler( _toDoItemMetrics = toDoItemMetrics; } - public async Task Handle(CreateTodoItemCommand request, CancellationToken cancellationToken) + public async ValueTask Handle(CreateTodoItemCommand request, CancellationToken cancellationToken) { var entity = request.MapToEntity(); diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/DeleteTodoItem/DeleteTodoItemCommand.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/DeleteTodoItem/DeleteTodoItemCommand.cs index d4b827b..b0b2d47 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/DeleteTodoItem/DeleteTodoItemCommand.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/DeleteTodoItem/DeleteTodoItemCommand.cs @@ -11,7 +11,7 @@ public DeleteTodoItemCommandHandler(IToDoItemRepository toDoItemRepository) _toDoItemRepository = toDoItemRepository; } - public async Task Handle(DeleteTodoItemCommand request, CancellationToken cancellationToken) + public async ValueTask Handle(DeleteTodoItemCommand request, CancellationToken cancellationToken) { var entity = await _toDoItemRepository.GetByIdAsync(request.Id, cancellationToken) ?? throw new NotFoundException(nameof(TodoItem), request.Id); @@ -23,5 +23,7 @@ public async Task Handle(DeleteTodoItemCommand request, CancellationToken cancel await _toDoItemRepository.DeleteAsync(entity, cancellationToken); } + + return Unit.Value; } } diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/UpdateTodoItem/UpdateTodoItemCommand.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/UpdateTodoItem/UpdateTodoItemCommand.cs index a296ea4..fc42f6e 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/UpdateTodoItem/UpdateTodoItemCommand.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/Commands/UpdateTodoItem/UpdateTodoItemCommand.cs @@ -18,7 +18,7 @@ public UpdateTodoItemCommandHandler(IToDoItemRepository toDoItemRepository) _toDoItemRepository = toDoItemRepository; } - public async Task Handle(UpdateTodoItemCommand request, CancellationToken cancellationToken) + public async ValueTask Handle(UpdateTodoItemCommand request, CancellationToken cancellationToken) { var entity = await _toDoItemRepository.GetByIdAsync(request.Id, cancellationToken) ?? throw new NotFoundException(nameof(TodoItem), request.Id); @@ -29,5 +29,7 @@ public async Task Handle(UpdateTodoItemCommand request, CancellationToken cancel await _toDoItemRepository.UpdateAsync(entity, cancellationToken); } + + return Unit.Value; } } diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemCreated/TodoItemCreatedEventHandler.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemCreated/TodoItemCreatedEventHandler.cs index f103053..8940896 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemCreated/TodoItemCreatedEventHandler.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemCreated/TodoItemCreatedEventHandler.cs @@ -9,10 +9,10 @@ public TodoItemCreatedEventHandler(ILogger logger) _logger = logger; } - public Task Handle(TodoItemCreatedEvent notification, CancellationToken cancellationToken) + public ValueTask Handle(TodoItemCreatedEvent notification, CancellationToken cancellationToken) { _logger.LogInformation("Domain Event: {DomainEvent}", nameof(TodoItemCreatedEvent)); - return Task.CompletedTask; + return ValueTask.CompletedTask; } } diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemDeleted/TodoItemDeletedEventHandler.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemDeleted/TodoItemDeletedEventHandler.cs index 1371450..3604d23 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemDeleted/TodoItemDeletedEventHandler.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/EventHandlers/TodoItemDeleted/TodoItemDeletedEventHandler.cs @@ -9,10 +9,10 @@ public TodoItemDeletedEventHandler(ILogger logger) _logger = logger; } - public Task Handle(TodoItemDeletedEvent notification, CancellationToken cancellationToken) + public ValueTask Handle(TodoItemDeletedEvent notification, CancellationToken cancellationToken) { _logger.LogInformation("Domain Event: {DomainEvent}", nameof(TodoItemDeletedEvent)); - return Task.CompletedTask; + return ValueTask.CompletedTask; } } diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetToDoItem/GetToDoItemQuery.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetToDoItem/GetToDoItemQuery.cs index 50bf682..97f5b8f 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetToDoItem/GetToDoItemQuery.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetToDoItem/GetToDoItemQuery.cs @@ -16,7 +16,7 @@ public GetToDoItemQueryHandler(IApplicationDbContext context) _context = context; } - public async Task Handle(GetToDoItemQuery request, CancellationToken cancellationToken) + public async ValueTask Handle(GetToDoItemQuery request, CancellationToken cancellationToken) { var data = await _context.TodoItems .AsNoTracking() diff --git a/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetTodoItemsWithPagination/GetTodoItemsWithPaginationQuery.cs b/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetTodoItemsWithPagination/GetTodoItemsWithPaginationQuery.cs index 25c0270..9e01c9e 100644 --- a/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetTodoItemsWithPagination/GetTodoItemsWithPaginationQuery.cs +++ b/src/MinimalApiTemplate.Application/Features/TodoItems/Queries/GetTodoItemsWithPagination/GetTodoItemsWithPaginationQuery.cs @@ -19,7 +19,7 @@ public GetTodoItemsWithPaginationQueryHandler(IApplicationDbContext context) _context = context; } - public async Task> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken) + public async ValueTask> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken) { var querableToDoItems = _context.TodoItems.AsNoTracking(); diff --git a/src/MinimalApiTemplate.Application/GlobalUsings.cs b/src/MinimalApiTemplate.Application/GlobalUsings.cs index c9323b0..fae22c1 100644 --- a/src/MinimalApiTemplate.Application/GlobalUsings.cs +++ b/src/MinimalApiTemplate.Application/GlobalUsings.cs @@ -2,7 +2,7 @@ global using Audit.Core; global using Riok.Mapperly.Abstractions; global using FluentValidation; -global using MediatR; +global using Mediator; global using Microsoft.Extensions.Logging; global using MinimalApiTemplate.Application.Common; global using MinimalApiTemplate.Application.Common.Exceptions; diff --git a/src/MinimalApiTemplate.Application/MinimalApiTemplate.Application.csproj b/src/MinimalApiTemplate.Application/MinimalApiTemplate.Application.csproj index 8fc8e51..6ea7e93 100644 --- a/src/MinimalApiTemplate.Application/MinimalApiTemplate.Application.csproj +++ b/src/MinimalApiTemplate.Application/MinimalApiTemplate.Application.csproj @@ -10,7 +10,10 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/MinimalApiTemplate.Domain/Common/BaseEvent.cs b/src/MinimalApiTemplate.Domain/Common/BaseEvent.cs index dc43982..b3b19ad 100644 --- a/src/MinimalApiTemplate.Domain/Common/BaseEvent.cs +++ b/src/MinimalApiTemplate.Domain/Common/BaseEvent.cs @@ -1,4 +1,4 @@ -using MediatR; +using Mediator; namespace MinimalApiTemplate.Domain.Common; diff --git a/src/MinimalApiTemplate.Domain/MinimalApiTemplate.Domain.csproj b/src/MinimalApiTemplate.Domain/MinimalApiTemplate.Domain.csproj index cb8eec6..2b3e067 100644 --- a/src/MinimalApiTemplate.Domain/MinimalApiTemplate.Domain.csproj +++ b/src/MinimalApiTemplate.Domain/MinimalApiTemplate.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/MinimalApiTemplate.Infrastructure/GlobalUsings.cs b/src/MinimalApiTemplate.Infrastructure/GlobalUsings.cs index a14b1de..855c6d0 100644 --- a/src/MinimalApiTemplate.Infrastructure/GlobalUsings.cs +++ b/src/MinimalApiTemplate.Infrastructure/GlobalUsings.cs @@ -9,4 +9,5 @@ global using MinimalApiTemplate.Domain.Enums; global using MinimalApiTemplate.Messages.Common; global using MassTransit; -global using Microsoft.Extensions.Logging; \ No newline at end of file +global using Microsoft.Extensions.Logging; +global using Mediator; \ No newline at end of file diff --git a/src/MinimalApiTemplate.Infrastructure/Persistence/Interceptors/DispatchDomainEventsInterceptor.cs b/src/MinimalApiTemplate.Infrastructure/Persistence/Interceptors/DispatchDomainEventsInterceptor.cs index d97b1d6..6e5df36 100644 --- a/src/MinimalApiTemplate.Infrastructure/Persistence/Interceptors/DispatchDomainEventsInterceptor.cs +++ b/src/MinimalApiTemplate.Infrastructure/Persistence/Interceptors/DispatchDomainEventsInterceptor.cs @@ -1,5 +1,4 @@ -using MediatR; -using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Diagnostics; namespace MinimalApiTemplate.Infrastructure.Persistence.Interceptors; diff --git a/tests/MinimalApiTemplate.Api.Tests/BaseTestFixture.cs b/tests/MinimalApiTemplate.Api.Tests/BaseTestFixture.cs index 0d3fce2..8b8eda1 100644 --- a/tests/MinimalApiTemplate.Api.Tests/BaseTestFixture.cs +++ b/tests/MinimalApiTemplate.Api.Tests/BaseTestFixture.cs @@ -1,5 +1,4 @@ -using MediatR; -using Microsoft.AspNetCore.OutputCaching; +using Microsoft.AspNetCore.OutputCaching; namespace MinimalApiTemplate.Api.Tests; diff --git a/tests/MinimalApiTemplate.Api.Tests/GlobalUsings.cs b/tests/MinimalApiTemplate.Api.Tests/GlobalUsings.cs index c578822..6f687c0 100644 --- a/tests/MinimalApiTemplate.Api.Tests/GlobalUsings.cs +++ b/tests/MinimalApiTemplate.Api.Tests/GlobalUsings.cs @@ -4,3 +4,4 @@ global using Microsoft.Extensions.Logging; global using NSubstitute; global using Xunit; +global using Mediator; diff --git a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/PerformanceBehaviourTests.cs b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/PerformanceBehaviourTests.cs index f5ae012..69e65cc 100644 --- a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/PerformanceBehaviourTests.cs +++ b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/PerformanceBehaviourTests.cs @@ -1,4 +1,5 @@ -using MediatR; +using Mediator; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using MinimalApiTemplate.Application.Common.Behaviours; using MinimalApiTemplate.Application.Common.Settings; @@ -10,31 +11,37 @@ public class PerformanceBehaviourTests private PerformanceBehaviour? _performanceBehaviour; private readonly ILogger _loggerMock = Substitute.For>(); private readonly ICurrentUserService _currentUserServiceMock = Substitute.For(); - private RequestHandlerDelegate? _pipelineBehaviourDelegateMock = null; + private readonly IServiceScopeFactory _serviceScopeFactoryMock = Substitute.For(); + private readonly IServiceScope _serviceScopeMock = Substitute.For(); + private MessageHandlerDelegate? _pipelineBehaviourDelegateMock = null; public PerformanceBehaviourTests() { + _serviceScopeFactoryMock.CreateScope().Returns(_serviceScopeMock); + + _serviceScopeMock.ServiceProvider.GetService().Returns(_currentUserServiceMock); + _currentUserServiceMock.UserId - .Returns("1"); + .Returns("1"); } public void Setup(AppSettings appSettings) { _performanceBehaviour = new(_loggerMock, - _currentUserServiceMock, + _serviceScopeFactoryMock, Options.Create(appSettings)); } - [Theory] + [Theory] [InlineData(false, 1, false, 0)] [InlineData(true, 10000, false, 5)] [InlineData(true, 1, true, 10)] public async Task When_ConditionsAreMet_Then_LogSlowRunningRequests( bool logRequests, int threshold, bool shouldHaveLog, int delay) { - _pipelineBehaviourDelegateMock = new RequestHandlerDelegate(async () => + _pipelineBehaviourDelegateMock = new MessageHandlerDelegate(async (input, ct) => { - await Task.Delay(delay); + await Task.Delay(delay, ct); return Unit.Value; }); @@ -54,8 +61,9 @@ public async Task When_ConditionsAreMet_Then_LogSlowRunningRequests( if (_performanceBehaviour is null) throw new NullReferenceException("Setup was not called"); await _performanceBehaviour.Handle(new PerformanceBehaviourTestInput(), - _pipelineBehaviourDelegateMock, - CancellationToken.None); + CancellationToken.None, + _pipelineBehaviourDelegateMock + ); _loggerMock.Received(shouldHaveLog ? 1 : 0) .Log(LogLevel.Warning, Arg.Any(), Arg.Any(), @@ -63,16 +71,7 @@ await _performanceBehaviour.Handle(new PerformanceBehaviourTestInput(), } } -public class PerformanceBehaviourTestInput : IRequest +public class PerformanceBehaviourTestInput : IRequest { } - -public class PerformanceBehaviourTestHandler : IRequestHandler -{ - public Task Handle(PerformanceBehaviourTestInput request, CancellationToken cancellationToken) - { - return Unit.Task; - } -} - diff --git a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/UnhandledExceptionBehaviourTests.cs b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/UnhandledExceptionBehaviourTests.cs index adf18f3..5802a68 100644 --- a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/UnhandledExceptionBehaviourTests.cs +++ b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/UnhandledExceptionBehaviourTests.cs @@ -1,4 +1,4 @@ -using MediatR; +using Mediator; using MinimalApiTemplate.Application.Common.Behaviours; using NSubstitute.ExceptionExtensions; @@ -8,7 +8,7 @@ public class UnhandledExceptionBehaviourTests { private readonly UnhandledExceptionBehaviour _unhandledExceptionBehaviour; private readonly ILogger _loggerMock = Substitute.For>(); - private readonly RequestHandlerDelegate _pipelineBehaviourDelegateMock = Substitute.For>(); + private readonly MessageHandlerDelegate _pipelineBehaviourDelegateMock = Substitute.For>(); public UnhandledExceptionBehaviourTests() @@ -19,12 +19,13 @@ public UnhandledExceptionBehaviourTests() [Fact] public async Task When_UnhandledExceptionIsThrown_Then_LogTheErrorMessage() { - _pipelineBehaviourDelegateMock.Invoke() + _pipelineBehaviourDelegateMock.Invoke(Arg.Any(), Arg.Any()) .Throws(new Exception("Unhandled exception")); await Assert.ThrowsAsync(() => _unhandledExceptionBehaviour.Handle(new UnhandledExceptionBehaviourTestInput(), - _pipelineBehaviourDelegateMock, - CancellationToken.None)); + CancellationToken.None, + _pipelineBehaviourDelegateMock + ).AsTask()); _loggerMock.Received() .Log(LogLevel.Error, Arg.Any(), Arg.Any(), @@ -32,15 +33,7 @@ await Assert.ThrowsAsync(() => _unhandledExceptionBehaviour.Handle(ne } } -public class UnhandledExceptionBehaviourTestInput : IRequest +public class UnhandledExceptionBehaviourTestInput : IRequest { -} - -public class UnhandledExceptionBehaviourTestHandler : IRequestHandler -{ - public Task Handle(UnhandledExceptionBehaviourTestInput request, CancellationToken cancellationToken) - { - return Unit.Task; - } } \ No newline at end of file diff --git a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/ValidationBehaviourTests.cs b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/ValidationBehaviourTests.cs index dd02125..c017a6b 100644 --- a/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/ValidationBehaviourTests.cs +++ b/tests/MinimalApiTemplate.Application.Tests/Common/Behaviours/ValidationBehaviourTests.cs @@ -1,5 +1,5 @@ using FluentValidation.Results; -using MediatR; +using Mediator; using MinimalApiTemplate.Application.Common.Behaviours; namespace MinimalApiTemplate.Application.Tests.Common.Behaviours; @@ -7,7 +7,7 @@ namespace MinimalApiTemplate.Application.Tests.Common.Behaviours; public class ValidationBehaviourTests { private readonly ValidationBehaviour _validationBehaviour; - private readonly RequestHandlerDelegate _pipelineBehaviourDelegateMock = Substitute.For>(); + private readonly MessageHandlerDelegate _pipelineBehaviourDelegateMock = Substitute.For>(); private readonly IValidator _validatorMock = Substitute.For>(); public ValidationBehaviourTests() @@ -26,26 +26,19 @@ public ValidationBehaviourTests() [Fact] public async Task When_ValidationExists_Then_ReturnTheErrorMessage() { - _pipelineBehaviourDelegateMock.Invoke() - .Returns(Unit.Value); + _pipelineBehaviourDelegateMock.Invoke(Arg.Any(), CancellationToken.None) + .Returns(Unit.ValueTask); - var sut = await Assert.ThrowsAsync(() => _validationBehaviour.Handle(new ValidationBehaviourTestInput(), - _pipelineBehaviourDelegateMock, - CancellationToken.None)); + var sut = await Assert.ThrowsAsync(() + => _validationBehaviour.Handle(new ValidationBehaviourTestInput(), + CancellationToken.None, + _pipelineBehaviourDelegateMock).AsTask()); sut.Errors.Count.Should().Be(1); } } -public class ValidationBehaviourTestInput : IRequest +public class ValidationBehaviourTestInput : IRequest { -} - -public class ValidationBehaviourTestHandler : IRequestHandler -{ - public Task Handle(ValidationBehaviourTestInput request, CancellationToken cancellationToken) - { - return Unit.Task; - } } \ No newline at end of file diff --git a/tests/MinimalApiTemplate.Application.Tests/Common/Events/BasePublishEventHanderTests.cs b/tests/MinimalApiTemplate.Application.Tests/Common/Events/BasePublishEventHanderTests.cs index 79443d7..d174519 100644 --- a/tests/MinimalApiTemplate.Application.Tests/Common/Events/BasePublishEventHanderTests.cs +++ b/tests/MinimalApiTemplate.Application.Tests/Common/Events/BasePublishEventHanderTests.cs @@ -1,4 +1,4 @@ -using MediatR; +using Mediator; using MinimalApiTemplate.Application.Common.Events; using MinimalApiTemplate.Messages.Common; diff --git a/tests/MinimalApiTemplate.Application.Tests/Features/ToDoItems/Commands/UpdateTodoItem/UpdateTodoItemCommandHandlerTests.cs b/tests/MinimalApiTemplate.Application.Tests/Features/ToDoItems/Commands/UpdateTodoItem/UpdateTodoItemCommandHandlerTests.cs index f860e86..d6c6f34 100644 --- a/tests/MinimalApiTemplate.Application.Tests/Features/ToDoItems/Commands/UpdateTodoItem/UpdateTodoItemCommandHandlerTests.cs +++ b/tests/MinimalApiTemplate.Application.Tests/Features/ToDoItems/Commands/UpdateTodoItem/UpdateTodoItemCommandHandlerTests.cs @@ -20,10 +20,12 @@ public async Task Given_IdDoesNotExists_Then_ThrowAnException() _templateRepositoryMock.GetByIdAsync(id, Arg.Any()) .ReturnsNull(); - await Assert.ThrowsAsync(() => - _handler.Handle(Builder.CreateNew() + var command = Builder.CreateNew() .With(x => id) - .Build(), CancellationToken.None)); + .Build(); + + await Assert.ThrowsAsync(() => + _handler.Handle(command, CancellationToken.None).AsTask()); await _templateRepositoryMock.DidNotReceive() .UpdateAsync(Arg.Any(), Arg.Any()); diff --git a/tests/MinimalApiTemplate.Infrastructure.Tests/BaseTestFixture.cs b/tests/MinimalApiTemplate.Infrastructure.Tests/BaseTestFixture.cs index d336728..a923cea 100644 --- a/tests/MinimalApiTemplate.Infrastructure.Tests/BaseTestFixture.cs +++ b/tests/MinimalApiTemplate.Infrastructure.Tests/BaseTestFixture.cs @@ -1,4 +1,4 @@ -using MediatR; +using Mediator; namespace MinimalApiTemplate.Infrastructure.Tests; diff --git a/tests/MinimalApiTemplate.Infrastructure.Tests/Persistence/Interceptors/DispatchDomainEventsInterceptorTests.cs b/tests/MinimalApiTemplate.Infrastructure.Tests/Persistence/Interceptors/DispatchDomainEventsInterceptorTests.cs index 8e9ff20..04c48b7 100644 --- a/tests/MinimalApiTemplate.Infrastructure.Tests/Persistence/Interceptors/DispatchDomainEventsInterceptorTests.cs +++ b/tests/MinimalApiTemplate.Infrastructure.Tests/Persistence/Interceptors/DispatchDomainEventsInterceptorTests.cs @@ -1,5 +1,4 @@ -using MediatR; -using MinimalApiTemplate.Domain.Common; +using MinimalApiTemplate.Domain.Common; using MinimalApiTemplate.Infrastructure.Persistence.Interceptors; namespace MinimalApiTemplate.Infrastructure.Tests.Persistence.Interceptors;