Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
pwelter34 authored Mar 28, 2024
2 parents d849b9a + a598bd9 commit 67b1443
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# FluentValidation
A library for using FluentValidation with Blazor

[![Nuget version](https://img.shields.io/nuget/v/Blazored.FluentValidation.svg?logo=nuget)](https://www.nuget.org/packages/Blazored.FluentValidation/)
[![Nuget downloads](https://img.shields.io/nuget/dt/Blazored.FluentValidation?logo=nuget)](https://www.nuget.org/packages/Blazored.FluentValidation/)
![Build & Test Main](https://github.com/Blazored/FluentValidation/workflows/Build%20&%20Test%20Main/badge.svg)

![Nuget](https://img.shields.io/nuget/v/blazored.fluentvalidation.svg)

## Installing

You can install from Nuget using the following command:
Expand Down Expand Up @@ -99,7 +99,7 @@ If you're using async validation, you can use the `ValidateAsync` method on the
private Person _person = new();
private FluentValidationValidator? _fluentValidationValidator;
private void SubmitFormAsync()
private async void SubmitFormAsync()
{
if (await _fluentValidationValidator!.ValidateAsync())
{
Expand Down Expand Up @@ -130,3 +130,31 @@ The second is when manually validating the model using the `Validate` or `Valida
=> _fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"));
}
```

## Access to full `ValidationFailure`
If you need details about the specifics of a validation result (e.g. its `Severity), you can access the result of the
last validation by calling the `GetFailuresFromLastValidation` method on the `FluentValidationValidator` component.

```razor
<div class="validation-message @GetValidationClass()">
<input type="text" @bind="@_person.Name" />
</div>
@code {
private FluentValidationValidator? _fluentValidationValidator;
private string GetValidationClass()
{
var lastResult = _fluentValidationValidator?.GetFailuresFromLastValidation();
if (lastResult is null || !lastResult.Any())
{
return "valid";
}
if (lastResult.Any(failure => failure.Severity == Severity.Error))
{
return "invalid";
}
return "warning";
}
}
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FluentValidation;
using FluentValidation.Internal;
using FluentValidation.Results;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.DependencyInjection;
using static FluentValidation.AssemblyScanner;
Expand Down Expand Up @@ -57,10 +58,21 @@ private static async Task ValidateModel(EditContext editContext,
var validationResults = await asyncValidationTask;

messages.Clear();
fluentValidationValidator.LastValidationResult = new Dictionary<FieldIdentifier, List<ValidationFailure>>();

foreach (var validationResult in validationResults.Errors)
{
var fieldIdentifier = ToFieldIdentifier(editContext, validationResult.PropertyName);
messages.Add(fieldIdentifier, validationResult.ErrorMessage);

if (fluentValidationValidator.LastValidationResult.TryGetValue(fieldIdentifier, out var failures))
{
failures.Add(validationResult);
}
else
{
fluentValidationValidator.LastValidationResult.Add(fieldIdentifier, new List<ValidationFailure> { validationResult });
}
}

editContext.NotifyValidationStateChanged();
Expand Down Expand Up @@ -187,6 +199,16 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in
var indexerValue = int.Parse(nextToken);
newObj = array[indexerValue];
}
else if (obj is IReadOnlyList<object> readOnlyList)
{
// Addresses an issue with collection expressions in C# 12 regarding IReadOnlyList:
// Generates a <>z__ReadOnlyArray which:
// - lacks an Item property, and
// - cannot be cast to object[] successfully.
// This workaround accesses elements directly using an indexer.
var indexerValue = int.Parse(nextToken);
newObj = readOnlyList[indexerValue];
}
else
{
throw new InvalidOperationException($"Could not find indexer on object of type {obj.GetType().FullName}.");
Expand Down
20 changes: 20 additions & 0 deletions src/Blazored.FluentValidation/FluentValidationsValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class FluentValidationValidator : ComponentBase
[Parameter] public bool DisableAssemblyScanning { get; set; }
[Parameter] public Action<ValidationStrategy<object>>? Options { get; set; }
internal Action<ValidationStrategy<object>>? ValidateOptions { get; set; }
internal Dictionary<FieldIdentifier, List<ValidationFailure>>? LastValidationResult { get; set; }

public bool Validate(Action<ValidationStrategy<object>>? options = null)
{
Expand Down Expand Up @@ -81,4 +82,23 @@ protected override void OnInitialized()

CurrentEditContext.AddFluentValidation(ServiceProvider, DisableAssemblyScanning, Validator, this);
}

/// <summary>
/// Gets the full details of the last validation result, optionally by field.
/// </summary>
/// <param name="fieldIdentifier">If set, only returns the validation failures pertaining to the given field.</param>
/// <returns>Validation failures.</returns>
public ValidationFailure[] GetFailuresFromLastValidation(FieldIdentifier? fieldIdentifier = null)
{
if (LastValidationResult is null)
return Array.Empty<ValidationFailure>();

if (fieldIdentifier is null)
return LastValidationResult.Values.SelectMany(f => f).ToArray();

if (!LastValidationResult.TryGetValue(fieldIdentifier.Value, out var failures))
return Array.Empty<ValidationFailure>();

return failures.ToArray();
}
}

0 comments on commit 67b1443

Please sign in to comment.