Skip to content

Instantly share code, notes, and snippets.

@PureKrome
Created May 8, 2023 05:42
Show Gist options
  • Save PureKrome/93ec506c7006a570025cd664e1bd38d9 to your computer and use it in GitHub Desktop.
Save PureKrome/93ec506c7006a570025cd664e1bd38d9 to your computer and use it in GitHub Desktop.
MediatR behavior not working
/*
Needs these package in the csproj
<ItemGroup>
<PackageReference Include="CSharpFunctionalExtensions" Version="2.38.1" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.5.2" />
<PackageReference Include="MediatR" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
*/
using CSharpFunctionalExtensions;
using FluentValidation;
using FluentValidation.Results;
using MediatR;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register our validators.
builder.Services.AddValidatorsFromAssemblyContaining<GetWeatherQuery.Validator>();
// Register our Mediator Handlers and behaviors.
builder.Services.AddMediatR(configuration =>
configuration
.RegisterServicesFromAssemblyContaining(typeof(Program))
//.AddOpenBehavior(typeof(ValidationBehavior <,>))
.AddBehavior<
IPipelineBehavior<GetWeatherQuery.Query, Result<GetWeatherQuery.Response, ValidationFailed>>,
ValidationBehavior<GetWeatherQuery.Query, GetWeatherQuery.Response>>()
);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.MapGet("/weatherforecast/{city:required}", async (
string city,
IMediator mediator,
CancellationToken cancellationToken) =>
{
var query = new GetWeatherQuery.Query(city);
var result = await mediator.Send(query, cancellationToken);
return TypedResults.Ok(result);
})
.WithOpenApi();
app.Run();
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
public class GetWeatherQuery
{
public record Query(string City) : IRequest<Response>;
public record Response(string City, int Temp, DateTime SomeDate);
public class Handler : IRequestHandler<Query, Response>
{
public Task<Response> Handle(Query request, CancellationToken cancellationToken)
{
var response = new Response("New York", 20, DateTime.Now);
return Task.FromResult(response);
}
}
public class Validator : AbstractValidator<Query>
{
public Validator()
{
RuleFor(x => x.City)
.NotEmpty()
.MinimumLength(5)
.WithMessage("City must be more than 5 characters.");
}
}
}
public record ValidationFailed
{
public IDictionary<string, string[]> Errors { get; }
public ValidationFailed(ValidationResult validationResult)
{
Errors = validationResult.ToDictionary();
}
}
public class ValidationBehavior<TRequest, TResult> :
IPipelineBehavior<TRequest, Result<TResult, ValidationFailed>> where TRequest : notnull
{
private readonly IValidator<TRequest> _validator;
public ValidationBehavior(IValidator<TRequest> validator)
{
_validator = validator;
}
public async Task<Result<TResult, ValidationFailed>> Handle(
TRequest request,
RequestHandlerDelegate<Result<TResult, ValidationFailed>> next,
CancellationToken cancellationToken)
{
var validationResult = await _validator.ValidateAsync(request, cancellationToken);
if (!validationResult.IsValid)
{
return new ValidationFailed(validationResult);
}
return await next();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment