Use JSON Property Name attributes when creating ModelState Validation errors
See original GitHub issueBackground and Motivation
Currently, when the model validation produces the ModelErrorDictionary it will use the property name as error’s key, as described in the example bellow, however in scenarios as SPA applications it can be difficult to handle the response since most of the time the property name is an implementation detail and not exactly what is expose through the JSON data.
public class Outer
{
[Range(1, 100)]
[JsonPropertyName("bar")]
public int Num { get; set; }
[Required]
public InnerClass SubClass { get; set; }
public class InnerClass
{
[Range(1,10)]
public int Test1 { get; set; }
}
}
{
"errors": {
"Num": [
"The field Num must be between 1 and 100."
],
"SubClass.Test1": [
"The field Test1 must be between 1 and 100."
]
}
}
Also, even when the JSON attributes are not used to define the property name the current implementation does not follow the JSON Naming Policy, that have been a complain since 2016 (#5590).
The proposal is to add two new Metadata Providers, JsonMetadataProvider
and NewtonsoftJsonMetadataProvider
, the last will be added when the AddNewtonsoftJson
is called while the first one could be added by the customer using the MvcOptions
. These new providers will be responsible for read from Newtonsoft.Json.JsonPropertyAttribute
or System.Text.Json.SerializationJsonPropertyNameAttribute
to set the new property ValidationMetadata.ValidationModelName
that will be used during the Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationEntry
creation.
When the new providers are included, the same example provided will produce the following result:
{
"errors": {
"bar": [
"The field bar must be between 1 and 100."
],
"subClass.test1": [
"The field test1 must be between 1 and 100."
]
}
}
Related:
Proposed API
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
+ /// <summary>
+ /// An implementation of <see cref="IDisplayMetadataProvider"/> and <see cref="IValidationMetadataProvider"/> for
+ /// the System.Text.Json.Serialization attribute classes.
+ /// </summary>
+ public class JsonMetadataProvider: IDisplayMetadataProvider, IValidationMetadataProvider
+ {
+ /// <summary>
+ /// Creates a new <see cref="JsonMetadataProvider"/> with the default <see cref="CamelCaseNamingStrategy"/>
+ /// </summary>
+ public JsonMetadataProvider()
+ /// <summary>
+ /// Creates a new <see cref="JsonMetadataProvider"/> with an optional <see cref="JsonNamingPolicy"/>
+ /// </summary>
+ /// <param name="namingPolicy">The <see cref="JsonNamingPolicy"/> to be used to configure the metadata provider.</param>
+ public JsonMetadataProvider(JsonNamingPolicy namingPolicy)
+ public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
+ public void CreateValidationMetadata(ValidationMetadataProviderContext context)
+ }
namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson;
+ /// <summary>
+ /// An implementation of <see cref="IDisplayMetadataProvider"/> and <see cref="IValidationMetadataProvider"/> for
+ /// the Newtonsoft.Json attribute classes.
+ /// </summary>
+ public class NewtonsoftJsonMetadataProvider : IDisplayMetadataProvider, IValidationMetadataProvider
+ {
+ /// <summary>
+ /// Creates a new <see cref="JsonMetadataProvider"/> with the default <see cref="CamelCaseNamingStrategy"/>
+ /// </summary>
+ public NewtonsoftJsonMetadataProvider()
+ /// <summary>
+ /// Initializes a new instance of <see cref="NewtonsoftJsonMetadataProvider"/> with an optional <see cref="NamingStrategy"/>
+ /// </summary>
+ /// <param name="namingStrategy">The <see cref="NamingStrategy"/> to be used to configure the metadata provider.</param>
+ public NewtonsoftJsonMetadataProvider(NamingStrategy namingStrategy)
+ public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
+ public void CreateValidationMetadata(ValidationMetadataProviderContext context)
+ }
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
{
public class ValidationMetadata
{
+ public string? ValidationModelName { get; set; }
}
}
Usage Examples
services..AddControllers(options => options.ModelMetadataDetailsProviders.Add(new JsonMetadataProvider()))
or
services.Configure<MvcOptions>(options =>
options.ModelMetadataDetailsProviders.Add(new JsonMetadataProvider(JsonNamingPolicy.CamelCase)));
Is also possible remove the default provider, if needed:
services.Configure<MvcOptions>(options => {
options.ModelMetadataDetailsProviders.RemoveType<NewtonsoftJsonMetadataProvider>();
});
Issue Analytics
- State:
- Created 2 years ago
- Reactions:6
- Comments:11 (8 by maintainers)
@niemyjski you can add the provider here:
https://github.com/exceptionless/Exceptionless/blob/940a04c28c74cad34221113a865a979510c2d432/src/Exceptionless.Web/Startup.cs#L48
Example:
@niemyjski can you share a sample app, so, I can provide what you need to do.
Right now we do not have plans to backport.