-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Respect JsonSerializerOptions in validation errors #62341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Hey @dotnet/aspnet-build, looks like this PR is something you want to take a look at. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request enhances JSON serialization and validation by applying JSON naming policies and attributes consistently, while also improving performance through caching and updating corresponding tests. Key changes include updating expected validation error keys to match JSON naming policies, caching of DisplayAttribute checks in property validation, and exposing JsonSerializerOptions via dependency injection.
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
src/Validation/test/Microsoft.Extensions.Validation.Tests/Microsoft.Extensions.Validation.Tests.csproj | Added dependency references for JSON serialization support. |
src/Validation/test/Microsoft.Extensions.Validation.GeneratorTests/*.cs | Updated expected error message keys in tests to lowercase according to the new naming policy. |
src/Validation/src/ValidateContext.cs | Exposed JsonSerializerOptions from DI and used new array literal initialization. |
src/Validation/src/ValidatableTypeInfo.cs | Uses JSON naming policy to format member names in validation errors. |
src/Validation/src/ValidatablePropertyInfo.cs | Integrated caching for DisplayAttribute and applied JSON naming policy consistently. |
src/Validation/src/Microsoft.Extensions.Validation.csproj | Updated dependency references. |
Comments suppressed due to low confidence (1)
src/Validation/src/ValidateContext.cs:71
- [nitpick] Ensure that the empty array literal '[]' properly initializes ValidationErrors as intended; if the target type is not directly inferrable, consider using 'new SomeType[0]' for clarity.
ValidationErrors ??= [];
@@ -28,12 +32,16 @@ protected ValidatablePropertyInfo( | |||
PropertyType = propertyType; | |||
Name = name; | |||
DisplayName = displayName; | |||
|
|||
// Cache the HasDisplayAttribute result to avoid repeated reflection calls | |||
var property = DeclaringType.GetProperty(Name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider specifying explicit BindingFlags (e.g. BindingFlags.Public | BindingFlags.Instance) with GetProperty to ensure the lookup behavior is unambiguous.
var property = DeclaringType.GetProperty(Name); | |
var property = DeclaringType.GetProperty(Name, BindingFlags.Public | BindingFlags.Instance); |
Copilot uses AI. Check for mistakes.
b5217e2
to
ee27af8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a test with a class with primary ctors and json attributes?
@@ -28,12 +32,16 @@ protected ValidatablePropertyInfo( | |||
PropertyType = propertyType; | |||
Name = name; | |||
DisplayName = displayName; | |||
|
|||
// Cache the HasDisplayAttribute result to avoid repeated reflection calls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Comment about why we don't use the name from the attribute
And maybe we should set DisplayName
to the attributes value if the provided value happens to be null? (I know the API definition says non-null but...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And maybe we should set DisplayName to the attributes value if the provided value happens to be null? (I know the API definition says non-null but...)
What would this help with?
} | ||
|
||
// Look for a constructor parameter matching the property name (case-insensitive) | ||
// to account for the record scenario |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and primary ctors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite since there isn't the same case-based 1:1 mapping between property names and parameter names when using primary constructors. It's a variation of #61526.
@@ -60,6 +64,8 @@ public sealed class ValidateContext | |||
/// </summary> | |||
public int CurrentDepth { get; set; } | |||
|
|||
internal JsonSerializerOptions? SerializerOptions => ValidationContext.GetService(typeof(IOptions<JsonOptions>)) is IOptions<JsonOptions> options ? options.Value.SerializerOptions : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal JsonSerializerOptions? SerializerOptions => ValidationContext.GetService(typeof(IOptions<JsonOptions>)) is IOptions<JsonOptions> options ? options.Value.SerializerOptions : null; | |
internal JsonSerializerOptions? SerializerOptions => ValidationContext.GetService<IOptions<JsonOptions>>()>?.Value.SerializerOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this works since you're embedding a local version of JsonOptions
into the package.
You should make a web app outside of the repo and test that this resolves the JsonOptions
from ConfigureHttpJsonOptions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was testing with this last night and trying to figure out how to get it to work in a console app. It turns out that using private reflection might be the only way to do this.
I force pushed the change since I hadn't realized you started reviewing it...
ee27af8
to
f29313d
Compare
This pull request introduces enhancements to JSON serialization and validation in the
Microsoft.Extensions.Validation
library. Key changes include improved handling of JSON naming policies, support forJsonPropertyName
attributes, and caching of reflection results to optimize performance. Additionally, test cases have been updated to reflect these changes.Enhancements to JSON Serialization and Validation:
Support for JSON Naming Policies and Attributes:
GetJsonPropertyName
to determine effective property names during JSON serialization, consideringJsonPropertyNameAttribute
and naming policies.JsonPropertyName
attributes for formatting property names and paths. [1] [2]Performance Optimization:
DisplayAttribute
in the constructor ofValidatablePropertyInfo
to avoid repeated reflection calls.HasDisplayAttribute
method to determine if a property or its corresponding record parameter has aDisplayAttribute
.Dependency and Context Updates:
Microsoft.AspNetCore.Http.Extensions
andSystem.Text.Json
for JSON serialization support. [1] [2] [3]JsonSerializerOptions
inValidateContext
to retrieve JSON naming policies from the DI container.Test Case Updates:
JsonPropertyName
attributes in validation error messages. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]