Skip to content

Commit 1ff6db3

Browse files
Fixes Problem Details casing bug (#59396) (#59876)
* Fixes Problem Details casing bug (#59396) * Apply suggestions from code review --------- Co-authored-by: Safia Abdalla <[email protected]>
1 parent 898c720 commit 1ff6db3

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

src/Http/Http.Extensions/src/DefaultProblemDetailsWriter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public ValueTask WriteAsync(ProblemDetailsContext context)
5656
ProblemDetailsDefaults.Apply(context.ProblemDetails, httpContext.Response.StatusCode);
5757

5858
var traceId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
59-
context.ProblemDetails.Extensions["traceId"] = traceId;
59+
var traceIdKeyName = _serializerOptions.PropertyNamingPolicy?.ConvertName("traceId") ?? "traceId";
60+
context.ProblemDetails.Extensions[traceIdKeyName] = traceId;
6061

6162
_options.CustomizeProblemDetails?.Invoke(context);
6263

src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public async Task WriteAsync_Works_ProperCasing()
8585
//Assert
8686
stream.Position = 0;
8787
var result = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(stream, JsonSerializerOptions.Default);
88-
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 }, {"traceId", expectedTraceId } }));
88+
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 }, { "traceId", expectedTraceId } }));
8989
}
9090

9191
[Fact]
@@ -117,7 +117,7 @@ public async Task WriteAsync_Works_ProperCasing_ValidationProblemDetails()
117117
//Assert
118118
stream.Position = 0;
119119
var result = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(stream, JsonSerializerOptions.Default);
120-
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 }, {"traceId", expectedTraceId } }));
120+
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 }, { "traceId", expectedTraceId } }));
121121
}
122122

123123
[Fact]
@@ -689,6 +689,57 @@ private static HttpContext CreateContext(
689689
return context;
690690
}
691691

692+
[Theory]
693+
[InlineData("SnakeCaseLower", "trace_id")]
694+
[InlineData("CamelCase", "traceId")]
695+
[InlineData("KebabCaseLower", "trace-id")]
696+
[InlineData("KebabCaseUpper", "TRACE-ID")]
697+
[InlineData("SnakeCaseUpper", "TRACE_ID")]
698+
public async Task TestPropertyNamingPolicyChanges(string caseSelection, string extensionVariableName)
699+
{
700+
// Arrange
701+
JsonNamingPolicy propertyNamingPolicy = caseSelection switch
702+
{
703+
"CamelCase" => JsonNamingPolicy.CamelCase,
704+
"KebabCaseLower" => JsonNamingPolicy.KebabCaseLower,
705+
"KebabCaseUpper" => JsonNamingPolicy.KebabCaseUpper,
706+
"SnakeCaseLower" => JsonNamingPolicy.SnakeCaseLower,
707+
"SnakeCaseUpper" => JsonNamingPolicy.SnakeCaseUpper,
708+
_ => JsonNamingPolicy.KebabCaseLower
709+
};
710+
711+
var options = new JsonOptions();
712+
options.SerializerOptions.PropertyNamingPolicy = propertyNamingPolicy;
713+
714+
var writer = GetWriter(jsonOptions: options);
715+
var stream = new MemoryStream();
716+
var context = CreateContext(stream);
717+
718+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
719+
var expectedProblem = new ProblemDetails()
720+
{
721+
Detail = "Custom Bad Request",
722+
Instance = "Custom Bad Request",
723+
Status = StatusCodes.Status400BadRequest,
724+
Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1-custom",
725+
Title = "Custom Bad Request",
726+
};
727+
var problemDetailsContext = new ProblemDetailsContext()
728+
{
729+
HttpContext = context,
730+
ProblemDetails = expectedProblem
731+
};
732+
733+
//Act
734+
await writer.WriteAsync(problemDetailsContext);
735+
stream.Position = 0;
736+
using var reader = new StreamReader(stream);
737+
var json = await reader.ReadToEndAsync();
738+
739+
//Assert
740+
Assert.Contains($"\"{extensionVariableName}\":\"{expectedTraceId}\"", json);
741+
}
742+
692743
private static IServiceProvider CreateServices()
693744
{
694745
var services = new ServiceCollection();

0 commit comments

Comments
 (0)