I have two worlds of validation mechanisms in my ASP.NET Core 3.1 application:
In
services.AddControllersWithViews
I add a customIValidationMetadataProvider
tooptions.ModelMetadataDetailsProviders
. It changes theErrorMessage
of the defaultValidationAttribute
s that are defined in my model classes to something that can be localised. This happens for all models that are validated through MVC model-binding. The results are in the usual place ofModelState
.Here's some code for that:
// In Startup.ConfigureServices: services.AddControllersWithViews(options => { options.ModelMetadataDetailsProviders.Add(new LocalizedValidationMetadataProvider()); }); internal class LocalizedValidationMetadataProvider : IValidationMetadataProvider { public void CreateValidationMetadata(ValidationMetadataProviderContext context) { foreach (object attribute in context.ValidationMetadata.ValidatorMetadata) { if (attribute is ValidationAttribute valAttr) { if (valAttr is RequiredAttribute reqAttr) reqAttr.ErrorMessage = "@input_required"; if (valAttr is MaxLengthAttribute maxLenAttr) maxLenAttr.ErrorMessage = $"@max_length {maxLenAttr.Length}"; } } } }
When reading and validating data from other sources (like importing from a JSON file), I use the
Validator
object to validate the models using their standardValidationAttribute
s and other mechanisms (IValidatableObject
). The results are in a local list ofValidationResult
s.Here's what I've done so far:
var vc = new ValidationContext(importedModel); var results = new List<ValidationResult>(); bool isValid = Validator.TryValidateObject(importedModel, vc, results, true); if (!isValid) { // Here I need results with the localisable messages like "@input_required" // Instead, I get the default "The (Name) field is required." }
Now the problem is that in the second case, the default messages for the ValidationAttribute
s are generated and in the ValidationResult
s I have no reference to the source of these messages. I need to integrate the first case somehow into the second scenario.
The IValidationMetadataProvider
implementation works on validation metadata found in a ValidationMetadataProviderContext
instance. I tried to trace down where that comes from and how MVC model-binding uses it but I am a bit lost in the aspnetcore source code with all its interfaces.
How would I bring the ValidationContext
of Validator
together with the ValidationMetadataProviderContext
of MVC?
Edit: Having read the relevant source code a bit further, I have the impression that it's not possible to use Validator
like this. Alternatively, how could I use MVC's ModelState
-related mechanisms for objects that did not come from a web form request but another arbitrary source? Can I tell one of MVC's classes to process an object as if it came from the request and through model binding?