Skip to content

Commit 9f4eb97

Browse files
authored
fixes minimal apis not returning traceid on problem details upon exceptions (#54478)
* fixes minimal apis not returning traceid on problem details upon exception (#54325) * rearrange usings and removes unnecessary usings
1 parent d4d6468 commit 9f4eb97

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Text.Json;
56
using Microsoft.AspNetCore.Http.Json;
67
using Microsoft.Extensions.Options;
@@ -53,6 +54,10 @@ public ValueTask WriteAsync(ProblemDetailsContext context)
5354
{
5455
var httpContext = context.HttpContext;
5556
ProblemDetailsDefaults.Apply(context.ProblemDetails, httpContext.Response.StatusCode);
57+
58+
var traceId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
59+
context.ProblemDetails.Extensions["traceId"] = traceId;
60+
5661
_options.CustomizeProblemDetails?.Invoke(context);
5762

5863
var problemDetailsType = context.ProblemDetails.GetType();

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

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Text.Json;
6+
using System.Text.Json.Serialization;
7+
using System.Text.Json.Serialization.Metadata;
58
using Microsoft.AspNetCore.Mvc;
69
using Microsoft.Extensions.DependencyInjection;
7-
using Microsoft.Extensions.Logging.Abstractions;
810
using Microsoft.Extensions.Logging;
11+
using Microsoft.Extensions.Logging.Abstractions;
912
using Microsoft.Extensions.Options;
10-
using System.Text.Json.Serialization.Metadata;
11-
using Microsoft.AspNetCore.Http.Json;
12-
using System.Text.Json.Serialization;
13-
using Microsoft.CodeAnalysis;
1413
using JsonOptions = Microsoft.AspNetCore.Http.Json.JsonOptions;
1514

1615
namespace Microsoft.AspNetCore.Http.Extensions.Tests;
@@ -26,6 +25,8 @@ public async Task WriteAsync_Works()
2625
var writer = GetWriter();
2726
var stream = new MemoryStream();
2827
var context = CreateContext(stream);
28+
29+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
2930
var expectedProblem = new ProblemDetails()
3031
{
3132
Detail = "Custom Bad Request",
@@ -52,6 +53,7 @@ public async Task WriteAsync_Works()
5253
Assert.Equal(expectedProblem.Title, problemDetails.Title);
5354
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
5455
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
56+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
5557
}
5658

5759
[Fact]
@@ -61,6 +63,7 @@ public async Task WriteAsync_Works_ProperCasing()
6163
var writer = GetWriter();
6264
var stream = new MemoryStream();
6365
var context = CreateContext(stream);
66+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
6467
var expectedProblem = new ProblemDetails()
6568
{
6669
Detail = "Custom Bad Request",
@@ -82,7 +85,7 @@ public async Task WriteAsync_Works_ProperCasing()
8285
//Assert
8386
stream.Position = 0;
8487
var result = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(stream, JsonSerializerOptions.Default);
85-
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 } }));
88+
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "extensionKey", 5 }, {"traceId", expectedTraceId } }));
8689
}
8790

8891
[Fact]
@@ -92,6 +95,7 @@ public async Task WriteAsync_Works_ProperCasing_ValidationProblemDetails()
9295
var writer = GetWriter();
9396
var stream = new MemoryStream();
9497
var context = CreateContext(stream);
98+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
9599
var expectedProblem = new ValidationProblemDetails()
96100
{
97101
Detail = "Custom Bad Request",
@@ -113,7 +117,7 @@ public async Task WriteAsync_Works_ProperCasing_ValidationProblemDetails()
113117
//Assert
114118
stream.Position = 0;
115119
var result = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(stream, JsonSerializerOptions.Default);
116-
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 } }));
120+
Assert.Equal(result.Keys, new(new() { { "type", 0 }, { "title", 1 }, { "status", 2 }, { "detail", 3 }, { "instance", 4 }, { "errors", 5 }, {"traceId", expectedTraceId } }));
117121
}
118122

119123
[Fact]
@@ -125,6 +129,7 @@ public async Task WriteAsync_Works_WhenReplacingProblemDetailsUsingSetter()
125129
var context = CreateContext(stream);
126130
var originalProblemDetails = new ProblemDetails();
127131

132+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
128133
var expectedProblem = new ProblemDetails()
129134
{
130135
Detail = "Custom Bad Request",
@@ -153,6 +158,7 @@ public async Task WriteAsync_Works_WhenReplacingProblemDetailsUsingSetter()
153158
Assert.Equal(expectedProblem.Title, problemDetails.Title);
154159
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
155160
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
161+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
156162
}
157163

158164
[Fact]
@@ -165,6 +171,7 @@ public async Task WriteAsync_Works_WithJsonContext()
165171
var writer = GetWriter(jsonOptions: options);
166172
var stream = new MemoryStream();
167173
var context = CreateContext(stream);
174+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
168175
var expectedProblem = new ProblemDetails()
169176
{
170177
Detail = "Custom Bad Request",
@@ -191,6 +198,7 @@ public async Task WriteAsync_Works_WithJsonContext()
191198
Assert.Equal(expectedProblem.Title, problemDetails.Title);
192199
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
193200
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
201+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
194202
}
195203

196204
[Fact]
@@ -203,6 +211,7 @@ public async Task WriteAsync_Works_WithMultipleJsonContext()
203211
var writer = GetWriter(jsonOptions: options);
204212
var stream = new MemoryStream();
205213
var context = CreateContext(stream);
214+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
206215
var expectedProblem = new ProblemDetails()
207216
{
208217
Detail = "Custom Bad Request",
@@ -229,6 +238,7 @@ public async Task WriteAsync_Works_WithMultipleJsonContext()
229238
Assert.Equal(expectedProblem.Title, problemDetails.Title);
230239
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
231240
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
241+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
232242
}
233243

234244
[Fact]
@@ -238,6 +248,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails()
238248
var writer = GetWriter();
239249
var stream = new MemoryStream();
240250
var context = CreateContext(stream);
251+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
241252
var expectedProblem = new HttpValidationProblemDetails()
242253
{
243254
Detail = "Custom Bad Request",
@@ -267,6 +278,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails()
267278
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
268279
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
269280
Assert.Equal(expectedProblem.Errors, problemDetails.Errors);
281+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
270282
}
271283

272284
[Fact]
@@ -279,6 +291,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails_AndJsonConte
279291
var writer = GetWriter(jsonOptions: options);
280292
var stream = new MemoryStream();
281293
var context = CreateContext(stream);
294+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
282295
var expectedProblem = new HttpValidationProblemDetails()
283296
{
284297
Detail = "Custom Bad Request",
@@ -308,6 +321,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails_AndJsonConte
308321
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
309322
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
310323
Assert.Equal(expectedProblem.Errors, problemDetails.Errors);
324+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
311325
}
312326

313327
[Fact]
@@ -320,6 +334,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails()
320334
var writer = GetWriter(jsonOptions: options);
321335
var stream = new MemoryStream();
322336
var context = CreateContext(stream);
337+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
323338
var expectedProblem = new CustomProblemDetails()
324339
{
325340
Detail = "Custom Bad Request",
@@ -349,6 +364,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails()
349364
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
350365
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
351366
Assert.Equal(expectedProblem.ExtraProperty, problemDetails.ExtraProperty);
367+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
352368
}
353369

354370
[Fact]
@@ -361,6 +377,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails_AndJsonContex
361377
var writer = GetWriter(jsonOptions: options);
362378
var stream = new MemoryStream();
363379
var context = CreateContext(stream);
380+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
364381
var expectedProblem = new CustomProblemDetails()
365382
{
366383
Detail = "Custom Bad Request",
@@ -390,6 +407,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails_AndJsonContex
390407
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
391408
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
392409
Assert.Equal(expectedProblem.ExtraProperty, problemDetails.ExtraProperty);
410+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
393411
}
394412

395413
[Fact]
@@ -402,6 +420,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails_AndMultipleJs
402420
var writer = GetWriter(jsonOptions: options);
403421
var stream = new MemoryStream();
404422
var context = CreateContext(stream);
423+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
405424
var expectedProblem = new CustomProblemDetails()
406425
{
407426
Detail = "Custom Bad Request",
@@ -431,6 +450,7 @@ public async Task WriteAsync_Works_WithCustomDerivedProblemDetails_AndMultipleJs
431450
Assert.Equal(expectedProblem.Detail, problemDetails.Detail);
432451
Assert.Equal(expectedProblem.Instance, problemDetails.Instance);
433452
Assert.Equal(expectedProblem.ExtraProperty, problemDetails.ExtraProperty);
453+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
434454
}
435455

436456
[Fact]
@@ -441,6 +461,7 @@ public async Task WriteAsync_AddExtensions()
441461
var stream = new MemoryStream();
442462
var context = CreateContext(stream);
443463
var expectedProblem = new ProblemDetails();
464+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
444465
expectedProblem.Extensions["Extension1"] = "Extension1-Value";
445466
expectedProblem.Extensions["Extension2"] = "Extension2-Value";
446467

@@ -467,6 +488,11 @@ public async Task WriteAsync_AddExtensions()
467488
{
468489
Assert.Equal("Extension2", extension.Key);
469490
Assert.Equal("Extension2-Value", extension.Value.ToString());
491+
},
492+
(extension) =>
493+
{
494+
Assert.Equal("traceId", extension.Key);
495+
Assert.Equal(expectedTraceId, extension.Value.ToString());
470496
});
471497
}
472498

@@ -482,6 +508,7 @@ public async Task WriteAsync_AddExtensions_WithJsonContext()
482508
var context = CreateContext(stream);
483509
var expectedProblem = new ProblemDetails();
484510
var customExtensionData = new CustomExtensionData("test");
511+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
485512
expectedProblem.Extensions["Extension"] = customExtensionData;
486513

487514
var problemDetailsContext = new ProblemDetailsContext()
@@ -507,6 +534,11 @@ public async Task WriteAsync_AddExtensions_WithJsonContext()
507534
var value = Assert.IsType<JsonElement>(extension.Value);
508535

509536
Assert.Equal(expectedExtension.GetProperty("data").GetString(), value.GetProperty("data").GetString());
537+
},
538+
(extension) =>
539+
{
540+
Assert.Equal("traceId", extension.Key);
541+
Assert.Equal(expectedTraceId, extension.Value.ToString());
510542
});
511543
}
512544

@@ -517,6 +549,7 @@ public async Task WriteAsync_Applies_Defaults()
517549
var writer = GetWriter();
518550
var stream = new MemoryStream();
519551
var context = CreateContext(stream, StatusCodes.Status500InternalServerError);
552+
var expectedTraceId = Activity.Current?.Id ?? context.TraceIdentifier;
520553

521554
//Act
522555
await writer.WriteAsync(new ProblemDetailsContext() { HttpContext = context });
@@ -528,19 +561,22 @@ public async Task WriteAsync_Applies_Defaults()
528561
Assert.Equal(StatusCodes.Status500InternalServerError, problemDetails.Status);
529562
Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", problemDetails.Type);
530563
Assert.Equal("An error occurred while processing your request.", problemDetails.Title);
564+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
531565
}
532566

533567
[Fact]
534568
public async Task WriteAsync_Applies_CustomConfiguration()
535569
{
536570
// Arrange
571+
const string expectedTraceId = "new-traceId-Value";
537572
var options = new ProblemDetailsOptions()
538573
{
539574
CustomizeProblemDetails = (context) =>
540575
{
541576
context.ProblemDetails.Status = StatusCodes.Status406NotAcceptable;
542577
context.ProblemDetails.Title = "Custom Title";
543578
context.ProblemDetails.Extensions["new-extension"] = new { TraceId = Guid.NewGuid() };
579+
context.ProblemDetails.Extensions["traceId"] = expectedTraceId;
544580
}
545581
};
546582
var writer = GetWriter(options);
@@ -562,6 +598,7 @@ await writer.WriteAsync(new ProblemDetailsContext()
562598
Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", problemDetails.Type);
563599
Assert.Equal("Custom Title", problemDetails.Title);
564600
Assert.Contains("new-extension", problemDetails.Extensions);
601+
Assert.Equal(expectedTraceId, problemDetails.Extensions["traceId"].ToString());
565602
}
566603

567604
[Theory]

0 commit comments

Comments
 (0)