Reputation: 51
My code is :
public class UniqueEmailPropertyValidator : FluentValidationModelValidatorProvider
{
public UniqueEmailPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
if (!this.ShouldGenerateClientSideRules())
yield break;
var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyName);
string message = formatter.BuildMessage(Validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule
{
ValidationType = "remote",
ErrorMessage = message
};
rule.ValidationParameters.Add("url", "/api/validation/uniqueemail");
yield return rule;
}
Now the error is :
FluentValidationModelValidatorProvider is not accessible due to its protection level
Upvotes: 3
Views: 1024
Reputation: 19156
First create your server-side validator
using FluentValidation.Validators;
using FluentValidationSample.Services;
namespace FluentValidationSample.ModelsValidations
{
public class UniqueEmailValidator : PropertyValidator
{
private readonly IUsersService _usersService;
public UniqueEmailValidator(IUsersService usersService)
: base("It's already in use.")
{
_usersService = usersService;
}
protected override bool IsValid(PropertyValidatorContext context)
{
return context.PropertyValue != null &&
_usersService.IsUniqueEmail((string)context.PropertyValue);
}
}
}
Then create a ClientValidator to produce the required metadata:
using FluentValidation;
using FluentValidation.AspNetCore;
using FluentValidation.Internal;
using FluentValidation.Resources;
using FluentValidation.Validators;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace FluentValidationSample.ModelsValidations
{
public class RemoteClientValidator : ClientValidatorBase
{
public string RemoteUrl { set; get; }
public RemoteClientValidator(PropertyRule rule, IPropertyValidator validator) :
base(rule, validator)
{
}
public override void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-remote", GetErrorMessage(context));
MergeAttribute(context.Attributes, "data-val-remote-url", RemoteUrl);
}
private string GetErrorMessage(ClientModelValidationContext context)
{
var formatter = ValidatorOptions.MessageFormatterFactory().AppendPropertyName(Rule.GetDisplayName());
string messageTemplate;
try
{
messageTemplate = Validator.Options.ErrorMessageSource.GetString(null);
}
catch (FluentValidationMessageFormatException)
{
messageTemplate = ValidatorOptions.LanguageManager.GetStringForValidator<NotEmptyValidator>();
}
return formatter.BuildMessage(messageTemplate);
}
}
}
Finally introduce them to system:
namespace FluentValidationSample.Web
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUsersService, UsersService>();
services.AddControllersWithViews().AddFluentValidation(
fv =>
{
fv.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly());
fv.RegisterValidatorsFromAssemblyContaining<RegisterModelValidator>();
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
fv.ConfigureClientsideValidation(clientSideValidation =>
{
// ...
clientSideValidation.Add(
validatorType: typeof(UniqueEmailValidator),
factory: (context, rule, validator) =>
new RemoteClientValidator(rule, validator)
{
RemoteUrl = "/Home/ValidateUniqueEmail"
});
});
}
);
}
Upvotes: 3