@@ -14,6 +14,8 @@ namespace Microsoft.AspNetCore.Http.Validation;
14
14
[ Experimental ( "ASP0029" , UrlFormat = "https://aka.ms/aspnet/analyzer/{0}" ) ]
15
15
public sealed class ValidateContext
16
16
{
17
+ private JsonNamingPolicy ? _cachedNamingPolicy ;
18
+ private bool _namingPolicyCached ;
17
19
/// <summary>
18
20
/// Gets or sets the validation context used for validating objects that implement <see cref="IValidatableObject"/> or have <see cref="ValidationAttribute"/>.
19
21
/// This context provides access to service provider and other validation metadata.
@@ -67,7 +69,34 @@ public sealed class ValidateContext
67
69
/// When available, property names in validation errors will be formatted according to the
68
70
/// PropertyNamingPolicy and JsonPropertyName attributes.
69
71
/// </summary>
70
- public JsonSerializerOptions ? SerializerOptions { get ; set ; }
72
+ public JsonSerializerOptions ? SerializerOptions
73
+ {
74
+ get => _serializerOptions ;
75
+ set
76
+ {
77
+ _serializerOptions = value ;
78
+ // Invalidate cache when SerializerOptions changes
79
+ _namingPolicyCached = false ;
80
+ _cachedNamingPolicy = null ;
81
+ }
82
+ }
83
+ private JsonSerializerOptions ? _serializerOptions ;
84
+
85
+ /// <summary>
86
+ /// Gets the cached naming policy from SerializerOptions to avoid repeated property access.
87
+ /// </summary>
88
+ private JsonNamingPolicy ? CachedNamingPolicy
89
+ {
90
+ get
91
+ {
92
+ if ( ! _namingPolicyCached )
93
+ {
94
+ _cachedNamingPolicy = _serializerOptions ? . PropertyNamingPolicy ;
95
+ _namingPolicyCached = true ;
96
+ }
97
+ return _cachedNamingPolicy ;
98
+ }
99
+ }
71
100
72
101
internal void AddValidationError ( string key , string [ ] errors )
73
102
{
@@ -114,7 +143,8 @@ internal void AddOrExtendValidationError(string key, string error)
114
143
115
144
private string FormatKey ( string key )
116
145
{
117
- if ( string . IsNullOrEmpty ( key ) || SerializerOptions ? . PropertyNamingPolicy is null )
146
+ var namingPolicy = CachedNamingPolicy ;
147
+ if ( string . IsNullOrEmpty ( key ) || namingPolicy is null )
118
148
{
119
149
return key ;
120
150
}
@@ -123,21 +153,20 @@ private string FormatKey(string key)
123
153
// apply the naming policy to each part of the path
124
154
if ( key . Contains ( '.' ) || key . Contains ( '[' ) )
125
155
{
126
- return FormatComplexKey ( key ) ;
156
+ return FormatComplexKey ( key , namingPolicy ) ;
127
157
}
128
158
129
159
// Apply the naming policy directly
130
- return SerializerOptions . PropertyNamingPolicy . ConvertName ( key ) ;
160
+ return namingPolicy . ConvertName ( key ) ;
131
161
}
132
162
133
- private string FormatComplexKey ( string key )
163
+ private static string FormatComplexKey ( string key , JsonNamingPolicy namingPolicy )
134
164
{
135
165
// Use a more direct approach for complex keys with dots and array indices
136
166
var result = new System . Text . StringBuilder ( ) ;
137
167
int lastIndex = 0 ;
138
168
int i = 0 ;
139
169
bool inBracket = false ;
140
- var propertyNamingPolicy = SerializerOptions ? . PropertyNamingPolicy ;
141
170
142
171
while ( i < key . Length )
143
172
{
@@ -149,9 +178,7 @@ private string FormatComplexKey(string key)
149
178
if ( i > lastIndex )
150
179
{
151
180
string segment = key . Substring ( lastIndex , i - lastIndex ) ;
152
- string formattedSegment = propertyNamingPolicy is not null
153
- ? propertyNamingPolicy . ConvertName ( segment )
154
- : segment ;
181
+ string formattedSegment = namingPolicy . ConvertName ( segment ) ;
155
182
result . Append ( formattedSegment ) ;
156
183
}
157
184
@@ -178,9 +205,7 @@ private string FormatComplexKey(string key)
178
205
if ( i > lastIndex )
179
206
{
180
207
string segment = key . Substring ( lastIndex , i - lastIndex ) ;
181
- string formattedSegment = propertyNamingPolicy is not null
182
- ? propertyNamingPolicy . ConvertName ( segment )
183
- : segment ;
208
+ string formattedSegment = namingPolicy . ConvertName ( segment ) ;
184
209
result . Append ( formattedSegment ) ;
185
210
}
186
211
result . Append ( c ) ;
@@ -194,9 +219,9 @@ private string FormatComplexKey(string key)
194
219
if ( lastIndex < key . Length )
195
220
{
196
221
string segment = key . Substring ( lastIndex ) ;
197
- if ( ! inBracket && propertyNamingPolicy is not null )
222
+ if ( ! inBracket )
198
223
{
199
- segment = propertyNamingPolicy . ConvertName ( segment ) ;
224
+ segment = namingPolicy . ConvertName ( segment ) ;
200
225
}
201
226
result . Append ( segment ) ;
202
227
}
0 commit comments