Skip to content

Instantly share code, notes, and snippets.

View Cheranga's full-sized avatar

Cheranga Hatangala Cheranga

  • Melbourne, Australia
View GitHub Profile
using Demo.Products.Api;
using Demo.Products.Api.Core;
using Demo.Products.Api.Core.Filters;
using Demo.Products.Api.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services
.AddControllers(options => { options.Filters.Add<ApiValidationFilter>(); })
public static class FluentValidationExtensions
{
public static void RegisterValidatorsInAssembly(this IMvcBuilder builder, Assembly assembly)
{
builder.RegisterValidatorsInAssemblyList(assembly);
}
public static void RegisterValidatorsInAssemblyList(this IMvcBuilder builder, params Assembly[] assemblies)
{
var assemblyList = assemblies?.ToList() ?? new List<Assembly>();
public interface ICustomValidatorFactory
{
IValidator GetValidatorFor(Type type);
}
public class CustomValidatorFactory : ICustomValidatorFactory
{
private readonly IServiceProvider _serviceProvider;
public CustomValidatorFactory(IServiceProvider serviceProvider)
public static class ValidationResultExtensions
{
public static ProblemDetails ToProblemDetails(this IEnumerable<ValidationFailure> validationFailures)
{
var errors = validationFailures.ToDictionary(x => x.PropertyName, x => x.ErrorMessage);
var problemDetails = new ProblemDetails
{
Type = "ValidationError",
Detail = "invalid request, please check the error list for more details",
public class ApiValidationFilter : IAsyncActionFilter
{
private readonly ICustomValidatorFactory _validatorFactory;
public ApiValidationFilter(ICustomValidatorFactory validatorFactory)
{
_validatorFactory = validatorFactory;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
[HybridBindClass(new []{Source.Header, Source.Body})]
public class RequestDto
{
[HybridBindProperty(Source.Header, name: "X-Correlation-ID")]
public string CorrelationId { get; set; }
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
[ApiController]
public class CreateProductsController : ControllerBase
{
private readonly ICreateProductService _service;
public CreateProductsController(ICreateProductService service)
{
_service = service;
}
public class AddProductRequestDtoValidator : ModelValidatorBase<AddProductRequestDto>
{
public AddProductRequestDtoValidator()
{
RuleFor(x => x.Id).NotNull().NotEmpty().WithMessage("id is required");
RuleFor(x => x.Name).MustAsync(async (s, token) =>
{
// simulating an asynchronous call
await Task.Delay(TimeSpan.FromSeconds(1), token);
return !string.IsNullOrWhiteSpace(s);
using Demo.Products.Api;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers().AddHybridModelBinder();
Bootstrapper.RegisterDependencies(builder);
...
...
public static class Bootstrapper
{
public static void RegisterDependencies(WebApplicationBuilder builder)
{
// register fluent validation as part of the ASP.NET pipeline
builder.Services.AddValidatorsFromAssembly(typeof(Program).Assembly)
.AddFluentValidationAutoValidation();
builder.Services.AddSingleton<ICreateProductService, CreateProductService>();
}