17
17
using System . Security . Cryptography . X509Certificates ;
18
18
using System . Text ;
19
19
using System . Text . Json ;
20
+ using System . Text . Json . Nodes ;
20
21
using System . Text . Json . Serialization ;
22
+ using System . Text . Json . Serialization . Metadata ;
21
23
using Microsoft . AspNetCore . Builder ;
22
24
using Microsoft . AspNetCore . Http ;
23
25
using Microsoft . AspNetCore . Http . Features ;
31
33
using Microsoft . Extensions . Options ;
32
34
using Microsoft . Extensions . Primitives ;
33
35
using Moq ;
36
+ using Xunit . Abstractions ;
34
37
35
38
namespace Microsoft . AspNetCore . Routing . Internal ;
36
39
@@ -3070,6 +3073,122 @@ public async Task RequestDelegateWritesMembersFromChildTypesToJsonResponseBody(D
3070
3073
Assert . Equal ( "With type hierarchies!" , deserializedResponseBody ! . Child ) ;
3071
3074
}
3072
3075
3076
+ public static IEnumerable < object [ ] > PolymorphicResult
3077
+ {
3078
+ get
3079
+ {
3080
+ JsonTodoChild originalTodo = new ( )
3081
+ {
3082
+ Name = "Write even more tests!" ,
3083
+ Child = "With type hierarchies!" ,
3084
+ } ;
3085
+
3086
+ JsonTodo TestAction ( ) => originalTodo ;
3087
+
3088
+ Task < JsonTodo > TaskTestAction ( ) => Task . FromResult < JsonTodo > ( originalTodo ) ;
3089
+ async Task < JsonTodo > TaskTestActionAwaited ( )
3090
+ {
3091
+ await Task . Yield ( ) ;
3092
+ return originalTodo ;
3093
+ }
3094
+
3095
+ ValueTask < JsonTodo > ValueTaskTestAction ( ) => ValueTask . FromResult < JsonTodo > ( originalTodo ) ;
3096
+ async ValueTask < JsonTodo > ValueTaskTestActionAwaited ( )
3097
+ {
3098
+ await Task . Yield ( ) ;
3099
+ return originalTodo ;
3100
+ }
3101
+
3102
+ return new List < object [ ] >
3103
+ {
3104
+ new object [ ] { ( Func < JsonTodo > ) TestAction } ,
3105
+ new object [ ] { ( Func < Task < JsonTodo > > ) TaskTestAction } ,
3106
+ new object [ ] { ( Func < Task < JsonTodo > > ) TaskTestActionAwaited } ,
3107
+ new object [ ] { ( Func < ValueTask < JsonTodo > > ) ValueTaskTestAction } ,
3108
+ new object [ ] { ( Func < ValueTask < JsonTodo > > ) ValueTaskTestActionAwaited } ,
3109
+ } ;
3110
+ }
3111
+ }
3112
+
3113
+ [ Theory ]
3114
+ [ MemberData ( nameof ( PolymorphicResult ) ) ]
3115
+ public async Task RequestDelegateWritesMembersFromChildTypesToJsonResponseBody_WithJsonPolymorphicOptions ( Delegate @delegate )
3116
+ {
3117
+ var httpContext = CreateHttpContext ( ) ;
3118
+ httpContext . RequestServices = new ServiceCollection ( )
3119
+ . AddSingleton ( LoggerFactory )
3120
+ . AddSingleton ( Options . Create ( new JsonOptions ( ) ) )
3121
+ . BuildServiceProvider ( ) ;
3122
+ var responseBodyStream = new MemoryStream ( ) ;
3123
+ httpContext . Response . Body = responseBodyStream ;
3124
+
3125
+ var factoryResult = RequestDelegateFactory . Create ( @delegate ) ;
3126
+ var requestDelegate = factoryResult . RequestDelegate ;
3127
+
3128
+ await requestDelegate ( httpContext ) ;
3129
+
3130
+ var deserializedResponseBody = JsonSerializer . Deserialize < JsonTodoChild > ( responseBodyStream . ToArray ( ) , new JsonSerializerOptions
3131
+ {
3132
+ PropertyNameCaseInsensitive = true
3133
+ } ) ;
3134
+
3135
+ Assert . NotNull ( deserializedResponseBody ) ;
3136
+ Assert . Equal ( "Write even more tests!" , deserializedResponseBody ! . Name ) ;
3137
+ Assert . Equal ( "With type hierarchies!" , deserializedResponseBody ! . Child ) ;
3138
+ }
3139
+
3140
+ [ Theory ]
3141
+ [ MemberData ( nameof ( PolymorphicResult ) ) ]
3142
+ public async Task RequestDelegateWritesMembersFromChildTypesToJsonResponseBody_WithJsonPolymorphicOptionsAndConfiguredJsonOptions ( Delegate @delegate )
3143
+ {
3144
+ var httpContext = CreateHttpContext ( ) ;
3145
+ httpContext . RequestServices = new ServiceCollection ( )
3146
+ . AddSingleton ( LoggerFactory )
3147
+ . AddSingleton ( Options . Create ( new JsonOptions ( ) ) )
3148
+ . BuildServiceProvider ( ) ;
3149
+ var responseBodyStream = new MemoryStream ( ) ;
3150
+ httpContext . Response . Body = responseBodyStream ;
3151
+
3152
+ var factoryResult = RequestDelegateFactory . Create ( @delegate , new RequestDelegateFactoryOptions { ServiceProvider = httpContext . RequestServices } ) ;
3153
+ var requestDelegate = factoryResult . RequestDelegate ;
3154
+
3155
+ await requestDelegate ( httpContext ) ;
3156
+
3157
+ var deserializedResponseBody = JsonSerializer . Deserialize < JsonTodoChild > ( responseBodyStream . ToArray ( ) , new JsonSerializerOptions
3158
+ {
3159
+ PropertyNameCaseInsensitive = true
3160
+ } ) ;
3161
+
3162
+ Assert . NotNull ( deserializedResponseBody ) ;
3163
+ Assert . Equal ( "Write even more tests!" , deserializedResponseBody ! . Name ) ;
3164
+ Assert . Equal ( "With type hierarchies!" , deserializedResponseBody ! . Child ) ;
3165
+ }
3166
+
3167
+ [ Theory ]
3168
+ [ MemberData ( nameof ( PolymorphicResult ) ) ]
3169
+ public async Task RequestDelegateWritesJsonTypeDiscriminatorToJsonResponseBody_WithJsonPolymorphicOptions ( Delegate @delegate )
3170
+ {
3171
+ var httpContext = CreateHttpContext ( ) ;
3172
+ httpContext . RequestServices = new ServiceCollection ( )
3173
+ . AddSingleton ( LoggerFactory )
3174
+ . AddSingleton ( Options . Create ( new JsonOptions ( ) ) )
3175
+ . BuildServiceProvider ( ) ;
3176
+
3177
+ var responseBodyStream = new MemoryStream ( ) ;
3178
+ httpContext . Response . Body = responseBodyStream ;
3179
+
3180
+ var factoryResult = RequestDelegateFactory . Create ( @delegate ) ;
3181
+ var requestDelegate = factoryResult . RequestDelegate ;
3182
+
3183
+ await requestDelegate ( httpContext ) ;
3184
+
3185
+ var deserializedResponseBody = JsonNode . Parse ( responseBodyStream . ToArray ( ) ) ;
3186
+
3187
+ Assert . NotNull ( deserializedResponseBody ) ;
3188
+ Assert . NotNull ( deserializedResponseBody [ "$type" ] ) ;
3189
+ Assert . Equal ( nameof ( JsonTodoChild ) , deserializedResponseBody [ "$type" ] ! . GetValue < string > ( ) ) ;
3190
+ }
3191
+
3073
3192
public static IEnumerable < object [ ] > JsonContextActions
3074
3193
{
3075
3194
get
@@ -3110,6 +3229,22 @@ public async Task RequestDelegateWritesAsJsonResponseBody_WithJsonSerializerCont
3110
3229
Assert . Equal ( "Write even more tests!" , deserializedResponseBody ! . Name ) ;
3111
3230
}
3112
3231
3232
+ [ Fact ]
3233
+ public void CreateDelegateThrows_WhenGetJsonTypeInfoFail ( )
3234
+ {
3235
+ var httpContext = CreateHttpContext ( ) ;
3236
+ httpContext . RequestServices = new ServiceCollection ( )
3237
+ . AddSingleton ( LoggerFactory )
3238
+ . ConfigureHttpJsonOptions ( o => o . SerializerOptions . AddContext < TestJsonContext > ( ) )
3239
+ . BuildServiceProvider ( ) ;
3240
+
3241
+ var responseBodyStream = new MemoryStream ( ) ;
3242
+ httpContext . Response . Body = responseBodyStream ;
3243
+
3244
+ TodoStruct TestAction ( ) => new TodoStruct ( 42 , "Bob" , true ) ;
3245
+ Assert . Throws < NotSupportedException > ( ( ) => RequestDelegateFactory . Create ( TestAction , new ( ) { ServiceProvider = httpContext . RequestServices } ) ) ;
3246
+ }
3247
+
3113
3248
public static IEnumerable < object [ ] > CustomResults
3114
3249
{
3115
3250
get
@@ -7526,6 +7661,11 @@ private class TodoChild : Todo
7526
7661
public string ? Child { get ; set ; }
7527
7662
}
7528
7663
7664
+ private class JsonTodoChild : JsonTodo
7665
+ {
7666
+ public string ? Child { get ; set ; }
7667
+ }
7668
+
7529
7669
private class CustomTodo : Todo
7530
7670
{
7531
7671
public static async ValueTask < CustomTodo ? > BindAsync ( HttpContext context , ParameterInfo parameter )
@@ -7539,6 +7679,8 @@ private class CustomTodo : Todo
7539
7679
}
7540
7680
}
7541
7681
7682
+ [ JsonPolymorphic ]
7683
+ [ JsonDerivedType ( typeof ( JsonTodoChild ) , nameof ( JsonTodoChild ) ) ]
7542
7684
private class JsonTodo : Todo
7543
7685
{
7544
7686
public static async ValueTask < JsonTodo ? > BindAsync ( HttpContext context , ParameterInfo parameter )
0 commit comments