Add contracts and endpoint filters

This commit is contained in:
Jens De Craecker 2025-07-28 12:09:11 +02:00
parent 94d4e1352f
commit cc5ed32cad
4 changed files with 81 additions and 0 deletions

View File

@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,14 @@
using System.Diagnostics.CodeAnalysis;
namespace Baguette.Extensions.AspNetCore.Mediator;
public interface IMediatorService
{
bool TryGetRequest(object? value, [NotNullWhen(true)] out IRequest? request);
bool TryGetRequest<TResponse>(object? value, [NotNullWhen(true)] out IRequest<TResponse>? request);
ValueTask SendAsync(IRequest request, CancellationToken cancellationToken = default);
ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);
}

View File

@ -0,0 +1,5 @@
namespace Baguette.Extensions.AspNetCore.Mediator;
public interface IRequest<out TResponse>;
public interface IRequest;

View File

@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Baguette.Extensions.AspNetCore.Mediator;
public class SendEndpointRequestFilter<TResponse> : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
var mediator = context.HttpContext.RequestServices.GetRequiredService<IMediatorService>();
var value = await next(context);
if (value is IResult)
return value;
if (!mediator.TryGetRequest<TResponse>(value, out var typedRequest))
throw new InvalidOperationException(); // TODO: Handle case where the request is not an IRequest
var response = await mediator.SendAsync(typedRequest, context.HttpContext.RequestAborted);
return response;
}
}
public class SendEndpointRequestFilter : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
var mediator = context.HttpContext.RequestServices.GetRequiredService<IMediatorService>();
var value = await next(context);
if (value is IResult)
return value;
if (!mediator.TryGetRequest(value, out var typedRequest))
throw new InvalidOperationException(); // TODO: Handle case where the request is not an IRequest
await mediator.SendAsync(typedRequest, context.HttpContext.RequestAborted);
return null;
}
}
public static class MediatorEndpointRouteBuilderExtensions
{
public static RouteHandlerBuilder SendRequest<TResponse>(this RouteHandlerBuilder builder)
{
return builder.AddEndpointFilter<SendEndpointRequestFilter<TResponse>>().Produces<TResponse>();
}
public static RouteHandlerBuilder SendRequest(this RouteHandlerBuilder builder)
{
return builder.AddEndpointFilter<SendEndpointRequestFilter>().Produces(StatusCodes.Status200OK);
}
}