question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using custom validators for validating nullable reference types

See original GitHub issue

Which version of FluentValidation are you using? 9.3.0

Issue description

  1. Nullable Reference Types enabled.
  2. Have a following classes
public class Data { ... }
public class Model {
    ...
    public Data? Data 
    ...
}

How to write validators in this case?

Option 1: Using non nullable reference type as type parameter:

public class DataValidator : AbstractValidator<Data> { ... }

But in this case we will get an error in Model Validator

public class ModelValidator : AbstractValidator<Model> 
{
    public ModelValidator () 
    {
        RuleFor(x => x.Data).SetValidator(new DataValidator ());
    }
}

This will generate following error on line with “SetValidator” call

Error CS8620 Argument of type 'DataValidator ' cannot be used for parameter 'validator' of type 'IValidator<Data?>' in 'IRuleBuilderOptions<Model, Data?> IRuleBuilder<Model, Data?>.SetValidator(IValidator<Data?> validator, params string[] ruleSets)' due to differences in the nullability of reference types.

Option 2: Using nullable reference type as type parameter:

public class DataValidator : AbstractValidator<Data?> 
{ 
    public DataValidator() 
    {
        RuleFor(x => x.SomeDataProperty)...
    }
}

This will raise Error CS8602 Dereference of a possibly null reference. at line with “RuleFor” call because it uses nullable reference type property without checking against null.

How to create validator correctly?

PS: Following code will compile but looks like hack fix to me (x!.SomeDataProperty)

public class DataValidator : AbstractValidator<Data?> 
{ 
    public DataValidator() 
    {
        RuleFor(x => x!.SomeDataProperty)...
    }
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
JeremySkinnercommented, Feb 26, 2021

Here’s an implementation of the same method that works on 10.0:

public static class DemoExtensions {
	public static IRuleBuilderOptions<T, TProperty?> SetNonNullableValidator<T, TProperty>(this IRuleBuilder<T, TProperty?> ruleBuilder, IValidator<TProperty> validator, params string[] ruleSets) {
		var adapter = new NullableChildValidatorAdaptor<T, TProperty>(validator, validator.GetType()) {
			RuleSets = ruleSets
		};

		return ruleBuilder.SetAsyncValidator((IAsyncPropertyValidator<T,TProperty?>)adapter);
	}

	private class NullableChildValidatorAdaptor<T, TProperty> : ChildValidatorAdaptor<T, TProperty>, IPropertyValidator<T, TProperty?>, IAsyncPropertyValidator<T,TProperty?> {
		public NullableChildValidatorAdaptor(IValidator<TProperty> validator, Type validatorType)
			: base(validator, validatorType) {
		}

		public override bool IsValid(ValidationContext<T> context, TProperty? value) {
			return base.IsValid(context, value!);
		}

		public override Task<bool> IsValidAsync(ValidationContext<T> context, TProperty? value, CancellationToken cancellation) {
			return base.IsValidAsync(context, value!, cancellation);
		}
	}
}

1reaction
VeselovAndreycommented, Feb 26, 2021

Took a fresh look today. And get rid of interface implementation and no need to inherit ChildValidatorAdaptor. It’s very simple solution:

public static IRuleBuilderOptions<TTarget, TProperty?> SetNonNullableValidator<TTarget, TProperty>(this IRuleBuilder<TTarget, TProperty?> ruleBuilder, IValidator<TProperty> validator, params string[] ruleSets)
{
	var adapter = new ChildValidatorAdaptor<TTarget, TProperty>(validator, validator.GetType())
	{
		RuleSets = ruleSets
	};

	return ruleBuilder.SetValidator(adapter);
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Object validation with nullable reference types in C# - ...
Basically, you'd check for every property if it's nullable, and if not, whether it then contains null . The way NRT annotations are...
Read more >
The best way to implement custom validators - Angular ...
Learning best practices on how to build your custom validator in Angular by reverse engineering the built-in Angular validators.
Read more >
Model validation in ASP.NET Core MVC and Razor Pages
The [ClassicMovie] attribute is a custom validation attribute and ... Use a nullable reference type to allow null or missing values to be ......
Read more >
Angular Custom Form Validators: Complete Guide
All about custom form validators, including synchronous and asynchronous, field-level, form-level, for both template-driven and reactive forms.
Read more >
DataAnnotations and Non-Nullable Required Inference - Blog
Invoking the ValidationContext class with our object to validate gives us ... NET Core 3.1, non-nullable reference types become implicitly ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found