Skip to content

Commit

Permalink
Allow default severity level to be set globally (#1715)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexTruba committed Apr 23, 2021
1 parent da45c4d commit b1e4402
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 19 deletions.
2 changes: 1 addition & 1 deletion docs/conditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ As well as being set at the rule level, the cascade mode can also be set globall
To set the cascade mode globally, you can set the `CascadeMode` property on the static `ValidatorOptions` class during your application's startup routine:

```csharp
ValidatorOptions.CascadeMode = CascadeMode.Stop;
ValidatorOptions.Global.CascadeMode = CascadeMode.Stop;
```

This can then be overridden by individual validator classes or by individual rules.
Expand Down
2 changes: 1 addition & 1 deletion docs/configuring.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ There is also an overload of `WithName` that accepts a lambda expression in a si
Property name resolution is also pluggable. By default, the name of the property extracted from the `MemberExpression` passed to `RuleFor`. If you want change this logic, you can set the `DisplayNameResolver` property on the `ValidatorOptions` class:

```csharp
ValidatorOptions.DisplayNameResolver = (type, member, expression) => {
ValidatorOptions.Global.DisplayNameResolver = (type, member, expression) => {
if(member != null) {
return member.Name + "Foo";
}
Expand Down
8 changes: 8 additions & 0 deletions docs/severity.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,11 @@ Property: Forename Severity: Error
```

By default, the severity level of every validation rule is `Error`. Available options are `Error`, `Warning`, or `Info`.

To set the severity level globally, you can set the `Severity` property on the static `ValidatorOptions` class during your application's startup routine:

```csharp
ValidatorOptions.Global.Severity = Severity.Info;
```

This can then be overridden by individual rules.
32 changes: 24 additions & 8 deletions src/FluentValidation.Tests/UserSeverityTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ namespace FluentValidation.Tests {
using System.Linq;
using Xunit;

public class UserSeverityTester {
public class UserSeverityTester : IDisposable {
TestValidator validator;

public UserSeverityTester()
{
public UserSeverityTester() {
ValidatorOptions.Global.Severity = Severity.Error;
validator = new TestValidator();
}

public void Dispose() {
ValidatorOptions.Global.Severity = Severity.Error;
}

[Fact]
public void Stores_user_severity_against_validation_failure() {
validator.RuleFor(x => x.Surname).NotNull().WithSeverity(Severity.Info);
Expand All @@ -39,14 +43,26 @@ public UserSeverityTester()

[Fact]
public void Defaults_user_severity_to_error() {
validator.RuleFor( x => x.Surname ).NotNull();
var result = validator.Validate( new Person() );
result.Errors.Single().Severity.ShouldEqual( Severity.Error );
validator.RuleFor(x => x.Surname).NotNull();
var result = validator.Validate(new Person());
result.Errors.Single().Severity.ShouldEqual(Severity.Error);
}

[Theory]
[InlineData(Severity.Error)]
[InlineData(Severity.Info)]
[InlineData(Severity.Warning)]
public void Defaults_user_severity_can_be_overridden_by_global_options(Severity severity) {
ValidatorOptions.Global.Severity = severity;

validator.RuleFor(x => x.Surname).NotNull();
var result = validator.Validate(new Person());
result.Errors.Single().Severity.ShouldEqual(severity);
}

[Fact]
public void Throws_when_provider_is_null() {
typeof(ArgumentNullException).ShouldBeThrownBy(() => validator.RuleFor(x => x.Surname).NotNull().WithSeverity((Func<Person, Severity>) null));
typeof(ArgumentNullException).ShouldBeThrownBy(() => validator.RuleFor(x => x.Surname).NotNull().WithSeverity((Func<Person, Severity>)null));
}

[Fact]
Expand All @@ -67,7 +83,7 @@ public UserSeverityTester()
[Fact]
public void Can_Provide_severity_for_item_in_collection() {
validator.RuleForEach(x => x.Children).NotNull().WithSeverity((person, child) => Severity.Warning);
var result = validator.Validate(new Person {Children = new List<Person> {null}});
var result = validator.Validate(new Person { Children = new List<Person> { null } });
result.Errors[0].Severity.ShouldEqual(Severity.Warning);
}

Expand Down
16 changes: 8 additions & 8 deletions src/FluentValidation/Internal/RuleBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace FluentValidation.Internal {
using Validators;

internal abstract class RuleBase<T, TProperty, TValue> : IValidationRule<T, TValue> {
private readonly List<RuleComponent<T,TValue>> _components = new();
private readonly List<RuleComponent<T, TValue>> _components = new();
private Func<CascadeMode> _cascadeModeThunk;
private string _propertyDisplayName;
private string _propertyName;
Expand Down Expand Up @@ -99,7 +99,7 @@ internal abstract class RuleBase<T, TProperty, TValue> : IValidationRule<T, TVal
/// <summary>
/// The current validator being configured by this rule.
/// </summary>
public RuleComponent<T,TValue> CurrentValidator => _components.LastOrDefault();
public RuleComponent<T, TValue> CurrentValidator => _components.LastOrDefault();

/// <summary>
/// The current rule component.
Expand Down Expand Up @@ -195,7 +195,7 @@ internal abstract class RuleBase<T, TProperty, TValue> : IValidationRule<T, TVal
/// <summary>
/// Allows custom creation of an error message
/// </summary>
public Func<MessageBuilderContext<T,TValue>, string> MessageBuilder { get; set; }
public Func<MessageBuilderContext<T, TValue>, string> MessageBuilder { get; set; }

/// <summary>
/// Dependent rules
Expand Down Expand Up @@ -310,7 +310,7 @@ public string GetDisplayName(ValidationContext<T> context)
/// <param name="value">The property value</param>
/// <param name="component">The current rule component.</param>
/// <returns>Returns an error validation result.</returns>
protected ValidationFailure CreateValidationError(ValidationContext<T> context, TValue value, RuleComponent<T,TValue> component) {
protected ValidationFailure CreateValidationError(ValidationContext<T> context, TValue value, RuleComponent<T, TValue> component) {
var error = MessageBuilder != null
? MessageBuilder(new MessageBuilderContext<T, TValue>(context, value, component))
: component.GetErrorMessage(context, value);
Expand All @@ -320,14 +320,14 @@ public string GetDisplayName(ValidationContext<T> context)
failure.FormattedMessagePlaceholderValues = new Dictionary<string, object>(context.MessageFormatter.PlaceholderValues);
failure.ErrorCode = component.ErrorCode ?? ValidatorOptions.Global.ErrorCodeResolver(component.Validator);

failure.Severity = component.SeverityProvider != null
? component.SeverityProvider(context, value)
: ValidatorOptions.Global.Severity;

if (component.CustomStateProvider != null) {
failure.CustomState = component.CustomStateProvider(context, value);
}

if (component.SeverityProvider != null) {
failure.Severity = component.SeverityProvider(context, value);
}

return failure;
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/FluentValidation/ValidatorOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public class ValidatorConfiguration {
/// </summary>
public CascadeMode CascadeMode { get; set; } = CascadeMode.Continue;

/// <summary>
/// Default severity level
/// </summary>
public Severity Severity { get; set; } = Severity.Error;

/// <summary>
/// Default property chain separator
/// </summary>
Expand Down Expand Up @@ -127,7 +132,7 @@ public static class ValidatorOptions {
public class ValidatorSelectorOptions {
private static readonly IValidatorSelector DefaultSelector = new DefaultValidatorSelector();

private Func<IValidatorSelector> _defaultValidatorSelector = () => DefaultSelector;
private Func<IValidatorSelector> _defaultValidatorSelector = () => DefaultSelector;
private Func<IEnumerable<string>, IValidatorSelector> _memberNameValidatorSelector = properties => new MemberNameValidatorSelector(properties);
private Func<IEnumerable<string>, IValidatorSelector> _rulesetValidatorSelector = ruleSets => new RulesetValidatorSelector(ruleSets);

Expand Down

0 comments on commit b1e4402

Please sign in to comment.