Skip to content

Commit 330d246

Browse files
Removing custom ProblemDetails Converters (#46492)
* Removing custom ProblemDetails Converters * Apply suggestions from code review Co-authored-by: Safia Abdalla <[email protected]> --------- Co-authored-by: Safia Abdalla <[email protected]>
1 parent 62c712c commit 330d246

20 files changed

+70
-363
lines changed

src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ Microsoft.AspNetCore.Http.HttpResponse</Description>
2626
<Compile Include="$(SharedSourceRoot)PropertyHelper\**\*.cs" />
2727
<Compile Include="$(SharedSourceRoot)\UrlDecoder\UrlDecoder.cs" Link="UrlDecoder.cs" />
2828
<Compile Include="$(SharedSourceRoot)ValueTaskExtensions\**\*.cs" />
29-
<Compile Include="$(SharedSourceRoot)ProblemDetails\HttpValidationProblemDetailsJsonConverter.cs" LinkBase="ProblemDetails\Converters" />
30-
<Compile Include="$(SharedSourceRoot)ProblemDetails\ProblemDetailsJsonConverter.cs" LinkBase="ProblemDetails\Converters" />
3129
<Compile Include="$(SharedSourceRoot)Reroute.cs" />
3230
</ItemGroup>
3331

src/Http/Http.Abstractions/src/ProblemDetails/HttpValidationProblemDetails.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
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.Text.Json.Serialization;
54
using Microsoft.AspNetCore.Mvc;
65

76
namespace Microsoft.AspNetCore.Http;
87

98
/// <summary>
109
/// A <see cref="ProblemDetails"/> for validation errors.
1110
/// </summary>
12-
[JsonConverter(typeof(HttpValidationProblemDetailsJsonConverter))]
1311
public class HttpValidationProblemDetails : ProblemDetails
1412
{
1513
/// <summary>
@@ -38,5 +36,5 @@ private HttpValidationProblemDetails(Dictionary<string, string[]> errors)
3836
/// <summary>
3937
/// Gets the validation errors associated with this instance of <see cref="HttpValidationProblemDetails"/>.
4038
/// </summary>
41-
public IDictionary<string, string[]> Errors { get; } = new Dictionary<string, string[]>(StringComparer.Ordinal);
39+
public IDictionary<string, string[]> Errors { get; set; } = new Dictionary<string, string[]>(StringComparer.Ordinal);
4240
}

src/Http/Http.Abstractions/src/ProblemDetails/ProblemDetails.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Text.Json.Serialization;
5-
using Microsoft.AspNetCore.Http;
65

76
namespace Microsoft.AspNetCore.Mvc;
87

98
/// <summary>
109
/// A machine-readable format for specifying errors in HTTP API responses based on <see href="https://tools.ietf.org/html/rfc7807"/>.
1110
/// </summary>
12-
[JsonConverter(typeof(ProblemDetailsJsonConverter))]
1311
public class ProblemDetails
1412
{
1513
/// <summary>
@@ -18,33 +16,38 @@ public class ProblemDetails
1816
/// (e.g., using HTML [W3C.REC-html5-20141028]). When this member is not present, its value is assumed to be
1917
/// "about:blank".
2018
/// </summary>
21-
[JsonPropertyName("type")]
19+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
20+
[JsonPropertyOrder(-5)]
2221
public string? Type { get; set; }
2322

2423
/// <summary>
2524
/// A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence
2625
/// of the problem, except for purposes of localization(e.g., using proactive content negotiation;
2726
/// see[RFC7231], Section 3.4).
2827
/// </summary>
29-
[JsonPropertyName("title")]
28+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
29+
[JsonPropertyOrder(-4)]
3030
public string? Title { get; set; }
3131

3232
/// <summary>
3333
/// The HTTP status code([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.
3434
/// </summary>
35-
[JsonPropertyName("status")]
35+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
36+
[JsonPropertyOrder(-3)]
3637
public int? Status { get; set; }
3738

3839
/// <summary>
3940
/// A human-readable explanation specific to this occurrence of the problem.
4041
/// </summary>
41-
[JsonPropertyName("detail")]
42+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
43+
[JsonPropertyOrder(-2)]
4244
public string? Detail { get; set; }
4345

4446
/// <summary>
4547
/// A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.
4648
/// </summary>
47-
[JsonPropertyName("instance")]
49+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
50+
[JsonPropertyOrder(-1)]
4851
public string? Instance { get; set; }
4952

5053
/// <summary>
@@ -59,5 +62,5 @@ public class ProblemDetails
5962
/// In particular, complex types or collection types may not round-trip to the original type when using the built-in JSON or XML formatters.
6063
/// </remarks>
6164
[JsonExtensionData]
62-
public IDictionary<string, object?> Extensions { get; } = new Dictionary<string, object?>(StringComparer.Ordinal);
65+
public IDictionary<string, object?> Extensions { get; set; } = new Dictionary<string, object?>(StringComparer.Ordinal);
6366
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#nullable enable
22
Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult
33
Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task!
4+
Microsoft.AspNetCore.Http.HttpValidationProblemDetails.Errors.set -> void
5+
Microsoft.AspNetCore.Mvc.ProblemDetails.Extensions.set -> void
46
static Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult!

src/Http/Http.Abstractions/test/HttpValidationProblemDetailsJsonConverterTest.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class HttpValidationProblemDetailsJsonConverterTest
1414
[Fact]
1515
public void Write_Works()
1616
{
17-
var converter = new HttpValidationProblemDetailsJsonConverter();
1817
var problemDetails = new HttpValidationProblemDetails();
1918

2019
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.5";
@@ -28,7 +27,7 @@ public void Write_Works()
2827

2928
var ms = new MemoryStream();
3029
var writer = new Utf8JsonWriter(ms);
31-
converter.Write(writer, problemDetails, JsonSerializerOptions);
30+
JsonSerializer.Serialize(writer, problemDetails, JsonSerializerOptions);
3231
writer.Flush();
3332

3433
ms.Seek(0, SeekOrigin.Begin);
@@ -57,13 +56,13 @@ public void Read_Works()
5756
var traceId = "|37dd3dd5-4a9619f953c40a16.";
5857
var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"detail\":\"{detail}\", \"instance\":\"{instance}\",\"traceId\":\"{traceId}\"," +
5958
"\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}";
60-
var converter = new HttpValidationProblemDetailsJsonConverter();
6159
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
6260
reader.Read();
6361

6462
// Act
65-
var problemDetails = converter.Read(ref reader, typeof(HttpValidationProblemDetails), JsonSerializerOptions);
63+
var problemDetails = JsonSerializer.Deserialize<HttpValidationProblemDetails>(ref reader, JsonSerializerOptions);
6664

65+
Assert.NotNull(problemDetails);
6766
Assert.Equal(type, problemDetails.Type);
6867
Assert.Equal(title, problemDetails.Title);
6968
Assert.Equal(status, problemDetails.Status);
@@ -100,13 +99,13 @@ public void Read_WithSomeMissingValues_Works()
10099
var traceId = "|37dd3dd5-4a9619f953c40a16.";
101100
var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"traceId\":\"{traceId}\"," +
102101
"\"errors\":{\"key0\":[\"error0\"],\"key1\":[\"error1\",\"error2\"]}}";
103-
var converter = new HttpValidationProblemDetailsJsonConverter();
104102
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
105103
reader.Read();
106104

107105
// Act
108-
var problemDetails = converter.Read(ref reader, typeof(HttpValidationProblemDetails), JsonSerializerOptions);
106+
var problemDetails = JsonSerializer.Deserialize<HttpValidationProblemDetails>(ref reader, JsonSerializerOptions);
109107

108+
Assert.NotNull(problemDetails);
110109
Assert.Equal(type, problemDetails.Type);
111110
Assert.Equal(title, problemDetails.Title);
112111
Assert.Equal(status, problemDetails.Status);

src/Http/Http.Abstractions/test/ProblemDetailsJsonConverterTest.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ public void Read_ThrowsIfJsonIsIncomplete()
1818
{
1919
// Arrange
2020
var json = "{";
21-
var converter = new ProblemDetailsJsonConverter();
2221

2322
// Act & Assert
2423
var ex = Record.Exception(() =>
2524
{
2625
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
27-
converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions);
26+
JsonSerializer.Deserialize(ref reader, typeof(ProblemDetails), JsonSerializerOptions);;
2827
});
2928
Assert.IsAssignableFrom<JsonException>(ex);
3029
}
@@ -40,14 +39,14 @@ public void Read_Works()
4039
var instance = "http://example.com/products/14";
4140
var traceId = "|37dd3dd5-4a9619f953c40a16.";
4241
var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"detail\":\"{detail}\", \"instance\":\"{instance}\",\"traceId\":\"{traceId}\"}}";
43-
var converter = new ProblemDetailsJsonConverter();
4442
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
4543
reader.Read();
4644

4745
// Act
48-
var problemDetails = converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions);
46+
var problemDetails = JsonSerializer.Deserialize<ProblemDetails>(ref reader, JsonSerializerOptions);
4947

5048
//Assert
49+
Assert.NotNull(problemDetails);
5150
Assert.Equal(type, problemDetails.Type);
5251
Assert.Equal(title, problemDetails.Title);
5352
Assert.Equal(status, problemDetails.Status);
@@ -135,14 +134,14 @@ public void Read_WithSomeMissingValues_Works()
135134
var status = 404;
136135
var traceId = "|37dd3dd5-4a9619f953c40a16.";
137136
var json = $"{{\"type\":\"{type}\",\"title\":\"{title}\",\"status\":{status},\"traceId\":\"{traceId}\"}}";
138-
var converter = new ProblemDetailsJsonConverter();
139137
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
140138
reader.Read();
141139

142140
// Act
143-
var problemDetails = converter.Read(ref reader, typeof(ProblemDetails), JsonSerializerOptions);
141+
var problemDetails = JsonSerializer.Deserialize<ProblemDetails>(ref reader, JsonSerializerOptions);
144142

145143
// Assert
144+
Assert.NotNull(problemDetails);
146145
Assert.Equal(type, problemDetails.Type);
147146
Assert.Equal(title, problemDetails.Title);
148147
Assert.Equal(status, problemDetails.Status);
@@ -174,13 +173,12 @@ public void Write_Works()
174173
}
175174
};
176175
var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status},\"detail\":\"{value.Detail}\",\"instance\":\"{JsonEncodedText.Encode(value.Instance)}\",\"traceId\":\"{traceId}\",\"some-data\":[\"value1\",\"value2\"]}}";
177-
var converter = new ProblemDetailsJsonConverter();
178176
var stream = new MemoryStream();
179177

180178
// Act
181179
using (var writer = new Utf8JsonWriter(stream))
182180
{
183-
converter.Write(writer, value, JsonSerializerOptions);
181+
JsonSerializer.Serialize(writer, value, JsonSerializerOptions);
184182
}
185183

186184
// Assert
@@ -199,13 +197,12 @@ public void Write_WithSomeMissingContent_Works()
199197
Status = 404,
200198
};
201199
var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status}}}";
202-
var converter = new ProblemDetailsJsonConverter();
203200
var stream = new MemoryStream();
204201

205202
// Act
206203
using (var writer = new Utf8JsonWriter(stream))
207204
{
208-
converter.Write(writer, value, JsonSerializerOptions);
205+
JsonSerializer.Serialize(writer, value, JsonSerializerOptions);
209206
}
210207

211208
// Assert
@@ -231,13 +228,12 @@ public void Write_WithNullExtensionValue_Works()
231228
}
232229
};
233230
var expected = $"{{\"type\":\"{JsonEncodedText.Encode(value.Type)}\",\"title\":\"{value.Title}\",\"status\":{value.Status},\"detail\":\"{value.Detail}\",\"instance\":\"{JsonEncodedText.Encode(value.Instance)}\",\"traceId\":null,\"some-data\":[\"value1\",\"value2\"]}}";
234-
var converter = new ProblemDetailsJsonConverter();
235231
var stream = new MemoryStream();
236232

237233
// Act
238234
using (var writer = new Utf8JsonWriter(stream))
239235
{
240-
converter.Write(writer, value, JsonSerializerOptions);
236+
JsonSerializer.Serialize(writer, value, JsonSerializerOptions);
241237
}
242238

243239
// Assert

src/Http/Http.Extensions/src/ProblemDetailsJsonContext.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ namespace Microsoft.AspNetCore.Http;
99

1010
[JsonSerializable(typeof(ProblemDetails))]
1111
[JsonSerializable(typeof(HttpValidationProblemDetails))]
12-
// ExtensionData
13-
[JsonSerializable(typeof(IDictionary<string, object?>))]
1412
// Additional values are specified on JsonSerializerContext to support some values for extensions.
1513
// For example, the DeveloperExceptionMiddleware serializes its complex type to JsonElement, which problem details then needs to serialize.
1614
[JsonSerializable(typeof(JsonElement))]
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#nullable enable
22
static Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(this Microsoft.AspNetCore.Http.HttpRequest! request, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<object?>
3-
static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, object? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
3+
static Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, object? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo! jsonTypeInfo, string? contentType = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
4+
Microsoft.AspNetCore.Mvc.ProblemDetails.Extensions.set -> void (forwarded, contained in Microsoft.AspNetCore.Http.Abstractions)
5+
Microsoft.AspNetCore.Http.HttpValidationProblemDetails.Errors.set -> void (forwarded, contained in Microsoft.AspNetCore.Http.Abstractions)

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ namespace Microsoft.AspNetCore.Http.Extensions.Tests;
1717

1818
public partial class DefaultProblemDetailsWriterTest
1919
{
20+
private static readonly JsonSerializerOptions SerializerOptions = JsonOptions.DefaultSerializerOptions;
21+
2022
[Fact]
2123
public async Task WriteAsync_Works()
2224
{
@@ -43,7 +45,7 @@ public async Task WriteAsync_Works()
4345

4446
//Assert
4547
stream.Position = 0;
46-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
48+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
4749
Assert.NotNull(problemDetails);
4850
Assert.Equal(expectedProblem.Status, problemDetails.Status);
4951
Assert.Equal(expectedProblem.Type, problemDetails.Type);
@@ -81,7 +83,7 @@ public async Task WriteAsync_Works_WithJsonContext()
8183

8284
//Assert
8385
stream.Position = 0;
84-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
86+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
8587
Assert.NotNull(problemDetails);
8688
Assert.Equal(expectedProblem.Status, problemDetails.Status);
8789
Assert.Equal(expectedProblem.Type, problemDetails.Type);
@@ -119,7 +121,7 @@ public async Task WriteAsync_Works_WithMultipleJsonContext()
119121

120122
//Assert
121123
stream.Position = 0;
122-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
124+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
123125
Assert.NotNull(problemDetails);
124126
Assert.Equal(expectedProblem.Status, problemDetails.Status);
125127
Assert.Equal(expectedProblem.Type, problemDetails.Type);
@@ -156,7 +158,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails()
156158

157159
//Assert
158160
stream.Position = 0;
159-
var problemDetails = await JsonSerializer.DeserializeAsync<HttpValidationProblemDetails>(stream);
161+
var problemDetails = await JsonSerializer.DeserializeAsync<HttpValidationProblemDetails>(stream, SerializerOptions);
160162
Assert.NotNull(problemDetails);
161163
Assert.Equal(expectedProblem.Status, problemDetails.Status);
162164
Assert.Equal(expectedProblem.Type, problemDetails.Type);
@@ -197,7 +199,7 @@ public async Task WriteAsync_Works_WithHttpValidationProblemDetails_AndJsonConte
197199

198200
//Assert
199201
stream.Position = 0;
200-
var problemDetails = await JsonSerializer.DeserializeAsync<HttpValidationProblemDetails>(stream);
202+
var problemDetails = await JsonSerializer.DeserializeAsync<HttpValidationProblemDetails>(stream, SerializerOptions);
201203
Assert.NotNull(problemDetails);
202204
Assert.Equal(expectedProblem.Status, problemDetails.Status);
203205
Assert.Equal(expectedProblem.Type, problemDetails.Type);
@@ -352,7 +354,7 @@ public async Task WriteAsync_AddExtensions()
352354

353355
//Assert
354356
stream.Position = 0;
355-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
357+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
356358
Assert.NotNull(problemDetails);
357359
Assert.Collection(problemDetails.Extensions,
358360
(extension) =>
@@ -393,7 +395,7 @@ public async Task WriteAsync_AddExtensions_WithJsonContext()
393395
//Assert
394396
stream.Position = 0;
395397

396-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
398+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, options.SerializerOptions);
397399
Assert.NotNull(problemDetails);
398400

399401
Assert.Collection(problemDetails.Extensions,
@@ -420,7 +422,7 @@ public async Task WriteAsync_Applies_Defaults()
420422

421423
//Assert
422424
stream.Position = 0;
423-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
425+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
424426
Assert.NotNull(problemDetails);
425427
Assert.Equal(StatusCodes.Status500InternalServerError, problemDetails.Status);
426428
Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.6.1", problemDetails.Type);
@@ -453,7 +455,7 @@ await writer.WriteAsync(new ProblemDetailsContext()
453455

454456
//Assert
455457
stream.Position = 0;
456-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
458+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
457459
Assert.NotNull(problemDetails);
458460
Assert.Equal(StatusCodes.Status406NotAcceptable, problemDetails.Status);
459461
Assert.Equal("https://tools.ietf.org/html/rfc9110#section-15.5.1", problemDetails.Type);
@@ -484,7 +486,7 @@ await writer.WriteAsync(new ProblemDetailsContext()
484486

485487
//Assert
486488
stream.Position = 0;
487-
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream);
489+
var problemDetails = await JsonSerializer.DeserializeAsync<ProblemDetails>(stream, SerializerOptions);
488490
Assert.NotNull(problemDetails);
489491
Assert.Equal(statusCode, problemDetails.Status);
490492
Assert.Equal(type, problemDetails.Type);

src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6019,7 +6019,7 @@ string HelloName(string name)
60196019
await requestDelegate(httpContext);
60206020

60216021
// Assert
6022-
var decodedResponseBody = JsonSerializer.Deserialize<Mvc.ProblemDetails>(responseBodyStream.ToArray());
6022+
var decodedResponseBody = JsonSerializer.Deserialize<Mvc.ProblemDetails>(responseBodyStream.ToArray(), JsonOptions.DefaultSerializerOptions);
60236023
Assert.Equal(400, httpContext.Response.StatusCode);
60246024
Assert.Equal("New response", decodedResponseBody!.Detail);
60256025
}

0 commit comments

Comments
 (0)