Skip to content

Instantly share code, notes, and snippets.

@karenpayneoregon
Last active October 3, 2025 22:19
Show Gist options
  • Select an option

  • Save karenpayneoregon/2651baf088497aadafd583c49dc10024 to your computer and use it in GitHub Desktop.

Select an option

Save karenpayneoregon/2651baf088497aadafd583c49dc10024 to your computer and use it in GitHub Desktop.
FluentValidation log validation errors as json

One page sample

public PageResult OnPostSubmit()
{
    // Perform validation
    var result = validator.Validate(Customer);
    if (!result.IsValid)
    {
        Log.Information("Validation failure on page {PageName} {@errors}", PageHelpers.GetCurrentPageName(HttpContext.Request), result.ToJson());
        result.AddToModelState(ModelState);
    }

    return Page();
}
using System.Text.Json;
using FluentValidation.Results;
namespace TODO.LanguageExtensions;
/// <summary>
/// Provides extension methods for FluentValidation to simplify validation and error handling.
/// </summary>
public static class FluentValidationExtensions
{
/// <summary>
/// Converts the validation failures in the <see cref="ValidationResult"/> into a dictionary
/// where the key is the property name and the value is a list of error messages associated with that property.
/// </summary>
/// <param name="result">The <see cref="ValidationResult"/> containing validation failures. Cannot be <see langword="null"/>.</param>
/// <returns>A dictionary where each key is a property name and the value is a list of error messages for that property.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="result"/> is <see langword="null"/>.</exception>
public static IDictionary<string, List<string>> ToErrorDictionary(this ValidationResult result) =>
result is null
? throw new ArgumentNullException(nameof(result))
: result.Errors
.GroupBy(f => f.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(f => f.ErrorMessage).ToList());
private static JsonSerializerOptions JsonSerializerOptions => new() { WriteIndented = true };
/// <summary>
/// Converts the validation failures in the <see cref="ValidationResult"/> into a JSON string.
/// </summary>
/// <param name="result">The <see cref="ValidationResult"/> containing validation failures. Cannot be <see langword="null"/>.</param>
/// <returns>A JSON string representing the validation failures, where each property name is associated with its list of error messages.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="result"/> is <see langword="null"/>.</exception>
public static string ToJson(this ValidationResult result) =>
result is null
? "{}"
: JsonSerializer.Serialize(result.ToErrorDictionary(), JsonSerializerOptions);
}
[2025-10-03 14:51:42.252 [Information] Validation failure on page "Index" "{
\"DateOfBirth\": [
\"\u0027Date Of Birth\u0027 is required.\"
],
\"FirstName\": [
\"First Name is required...\"
],
\"LastName\": [
\"Last Name is required...\"
],
\"Gender\": [
\"Please select Male or Female.\"
]
}"
/// <summary>
/// Provides helper methods for working with pages in an ASP.NET Core application.
/// </summary>
/// <remarks>
/// This class contains utility methods that assist in handling page-related operations,
/// such as retrieving the current page name from an HTTP request.
/// </remarks>
public class PageHelpers
{
/// <summary>
/// Retrieves the name of the current page based on the provided HTTP request.
/// </summary>
/// <param name="request">The <see cref="HttpRequest"/> object representing the current HTTP request. Cannot be <see langword="null"/>.</param>
/// <returns>
/// A <see cref="string"/> representing the name of the current page.
/// Returns "Index" if the request path is the root ("/"), otherwise returns the file name without its extension.
/// </returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="request"/> is <see langword="null"/>.</exception>
public static string GetCurrentPageName(HttpRequest request)
{
string path = request.Path;
return path == "/" ? "Index" : Path.GetFileNameWithoutExtension(path);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment