diff --git a/src/Http/Http.Extensions/src/DefaultProblemDetailsWriter.cs b/src/Http/Http.Extensions/src/DefaultProblemDetailsWriter.cs index 4d47a1e54f06..b02d719b9086 100644 --- a/src/Http/Http.Extensions/src/DefaultProblemDetailsWriter.cs +++ b/src/Http/Http.Extensions/src/DefaultProblemDetailsWriter.cs @@ -56,7 +56,8 @@ public ValueTask WriteAsync(ProblemDetailsContext context) ProblemDetailsDefaults.Apply(context.ProblemDetails, httpContext.Response.StatusCode); var traceId = Activity.Current?.Id ?? httpContext.TraceIdentifier; - context.ProblemDetails.Extensions["traceId"] = traceId; + var traceIdKeyName = _serializerOptions.PropertyNamingPolicy?.ConvertName("traceId") ?? "traceId"; + context.ProblemDetails.Extensions[traceIdKeyName] = traceId; _options.CustomizeProblemDetails?.Invoke(context); diff --git a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs index d57a440a4593..2afabbec3f06 100644 --- a/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs +++ b/src/Http/Http.Extensions/test/ProblemDetailsDefaultWriterTest.cs @@ -85,7 +85,7 @@ public async Task WriteAsync_Works_ProperCasing() //Assert stream.Position = 0; var result = await JsonSerializer.DeserializeAsync>(stream, JsonSerializerOptions.Default); - Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 }, {"traceId", expectedTraceId } })); + Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 }, { "traceId", expectedTraceId } })); } [Fact] @@ -117,7 +117,7 @@ public async Task WriteAsync_Works_ProperCasing_ValidationProblemDetails() //Assert stream.Position = 0; var result = await JsonSerializer.DeserializeAsync>(stream, JsonSerializerOptions.Default); - Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 }, {"traceId", expectedTraceId } })); + Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 }, { "traceId", expectedTraceId } })); } [Fact] @@ -689,6 +689,57 @@ private static HttpContext CreateContext( return context; } + [Theory] + [InlineData("SnakeCaseLower", "trace_id")] + [InlineData("CamelCase", "traceId")] + [InlineData("KebabCaseLower", "trace-id")] + [InlineData("KebabCaseUpper", "TRACE-ID")] + [InlineData("SnakeCaseUpper", "TRACE_ID")] + public async Task TestPropertyNamingPolicyChanges(string caseSelection, string extensionVariableName) + { + // Arrange + JsonNamingPolicy propertyNamingPolicy = caseSelection switch + { + "CamelCase" => JsonNamingPolicy.CamelCase, + "KebabCaseLower" => JsonNamingPolicy.KebabCaseLower, + "KebabCaseUpper" => JsonNamingPolicy.KebabCaseUpper, + "SnakeCaseLower" => JsonNamingPolicy.SnakeCaseLower, + "SnakeCaseUpper" => JsonNamingPolicy.SnakeCaseUpper, + _ => JsonNamingPolicy.KebabCaseLower + }; + + var options = new JsonOptions(); + options.SerializerOptions.PropertyNamingPolicy = propertyNamingPolicy; + + var writer = GetWriter(jsonOptions: options); + var stream = new MemoryStream(); + var context = CreateContext(stream); + + var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier; + var expectedProblem = new ProblemDetails() + { + Detail = "Custom Bad Request", + Instance = "Custom Bad Request", + Status = StatusCodes.Status400BadRequest, + Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1-custom", + Title = "Custom Bad Request", + }; + var problemDetailsContext = new ProblemDetailsContext() + { + HttpContext = context, + ProblemDetails = expectedProblem + }; + + //Act + await writer.WriteAsync(problemDetailsContext); + stream.Position = 0; + using var reader = new StreamReader(stream); + var json = await reader.ReadToEndAsync(); + + //Assert + Assert.Contains($"\"{extensionVariableName}\":\"{expectedTraceId}\"", json); + } + private static IServiceProvider CreateServices() { var services = new ServiceCollection();