Skip to content

Commit a94189e

Browse files
authored
Handle JsonExceptions in RequestDelegateFactory (#36589)
1 parent d0465d8 commit a94189e

File tree

2 files changed

+127
-46
lines changed

2 files changed

+127
-46
lines changed

src/Http/Http.Extensions/src/RequestDelegateFactory.cs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Reflection;
99
using System.Security.Claims;
1010
using System.Text;
11+
using System.Text.Json;
1112
using Microsoft.AspNetCore.Http.Features;
1213
using Microsoft.AspNetCore.Http.Metadata;
1314
using Microsoft.Extensions.DependencyInjection;
@@ -504,7 +505,7 @@ private static Expression AddResponseWritingToMethodCall(Expression methodCall,
504505

505506
private static Func<object?, HttpContext, Task> HandleRequestBodyAndCompileRequestDelegate(Expression responseWritingMethodCall, FactoryContext factoryContext)
506507
{
507-
if (factoryContext.JsonRequestBodyType is null)
508+
if (factoryContext.JsonRequestBodyParameter is null)
508509
{
509510
if (factoryContext.ParameterBinders.Count > 0)
510511
{
@@ -533,7 +534,12 @@ private static Expression AddResponseWritingToMethodCall(Expression methodCall,
533534
responseWritingMethodCall, TargetExpr, HttpContextExpr).Compile();
534535
}
535536

536-
var bodyType = factoryContext.JsonRequestBodyType;
537+
var bodyType = factoryContext.JsonRequestBodyParameter.ParameterType;
538+
var parameterTypeName = TypeNameHelper.GetTypeDisplayName(factoryContext.JsonRequestBodyParameter.ParameterType, fullName: false);
539+
var parameterName = factoryContext.JsonRequestBodyParameter.Name;
540+
541+
Debug.Assert(parameterName is not null, "CreateArgument() should throw if parameter.Name is null.");
542+
537543
object? defaultBodyValue = null;
538544

539545
if (factoryContext.AllowEmptyRequestBody && bodyType.IsValueType)
@@ -580,10 +586,10 @@ private static Expression AddResponseWritingToMethodCall(Expression methodCall,
580586
Log.RequestBodyIOException(httpContext, ex);
581587
return;
582588
}
583-
catch (InvalidDataException ex)
589+
catch (JsonException ex)
584590
{
585-
Log.RequestBodyInvalidDataException(httpContext, ex, factoryContext.ThrowOnBadRequest);
586-
httpContext.Response.StatusCode = 400;
591+
Log.InvalidJsonRequestBody(httpContext, parameterTypeName, parameterName, ex, factoryContext.ThrowOnBadRequest);
592+
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
587593
return;
588594
}
589595
}
@@ -618,10 +624,10 @@ private static Expression AddResponseWritingToMethodCall(Expression methodCall,
618624
Log.RequestBodyIOException(httpContext, ex);
619625
return;
620626
}
621-
catch (InvalidDataException ex)
627+
catch (JsonException ex)
622628
{
623629

624-
Log.RequestBodyInvalidDataException(httpContext, ex, factoryContext.ThrowOnBadRequest);
630+
Log.InvalidJsonRequestBody(httpContext, parameterTypeName, parameterName, ex, factoryContext.ThrowOnBadRequest);
625631
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
626632
return;
627633
}
@@ -879,11 +885,14 @@ private static Expression BindParameterFromBindAsync(ParameterInfo parameter, Fa
879885

880886
private static Expression BindParameterFromBody(ParameterInfo parameter, bool allowEmpty, FactoryContext factoryContext)
881887
{
882-
if (factoryContext.JsonRequestBodyType is not null)
888+
if (factoryContext.JsonRequestBodyParameter is not null)
883889
{
884890
factoryContext.HasMultipleBodyParameters = true;
885891
var parameterName = parameter.Name;
886-
if (parameterName is not null && factoryContext.TrackedParameters.ContainsKey(parameterName))
892+
893+
Debug.Assert(parameterName is not null, "CreateArgument() should throw if parameter.Name is null.");
894+
895+
if (factoryContext.TrackedParameters.ContainsKey(parameterName))
887896
{
888897
factoryContext.TrackedParameters.Remove(parameterName);
889898
factoryContext.TrackedParameters.Add(parameterName, "UNKNOWN");
@@ -892,7 +901,7 @@ private static Expression BindParameterFromBody(ParameterInfo parameter, bool al
892901

893902
var isOptional = IsOptionalParameter(parameter, factoryContext);
894903

895-
factoryContext.JsonRequestBodyType = parameter.ParameterType;
904+
factoryContext.JsonRequestBodyParameter = parameter;
896905
factoryContext.AllowEmptyRequestBody = allowEmpty || isOptional;
897906
factoryContext.Metadata.Add(new AcceptsMetadata(parameter.ParameterType, factoryContext.AllowEmptyRequestBody, DefaultAcceptsContentType));
898907

@@ -1164,7 +1173,7 @@ private class FactoryContext
11641173
public bool DisableInferredFromBody { get; init; }
11651174

11661175
// Temporary State
1167-
public Type? JsonRequestBodyType { get; set; }
1176+
public ParameterInfo? JsonRequestBodyParameter { get; set; }
11681177
public bool AllowEmptyRequestBody { get; set; }
11691178

11701179
public bool UsingTempSourceString { get; set; }
@@ -1197,7 +1206,8 @@ private static class RequestDelegateFactoryConstants
11971206

11981207
private static partial class Log
11991208
{
1200-
private const string RequestBodyInvalidDataExceptionMessage = "Reading the request body failed with an InvalidDataException.";
1209+
private const string InvalidJsonRequestBodyMessage = @"Failed to read parameter ""{ParameterType} {ParameterName}"" from the request body as JSON.";
1210+
private const string InvalidJsonRequestBodyExceptionMessage = @"Failed to read parameter ""{0} {1}"" from the request body as JSON.";
12011211

12021212
private const string ParameterBindingFailedLogMessage = @"Failed to bind parameter ""{ParameterType} {ParameterName}"" from ""{SourceValue}"".";
12031213
private const string ParameterBindingFailedExceptionMessage = @"Failed to bind parameter ""{0} {1}"" from ""{2}"".";
@@ -1207,6 +1217,7 @@ private static partial class Log
12071217

12081218
private const string UnexpectedContentTypeLogMessage = @"Expected a supported JSON media type but got ""{ContentType}"".";
12091219
private const string UnexpectedContentTypeExceptionMessage = @"Expected a supported JSON media type but got ""{0}"".";
1220+
12101221
private const string ImplicitBodyNotProvidedLogMessage = @"Implicit body inferred for parameter ""{ParameterName}"" but no body was provided. Did you mean to use a Service instead?";
12111222
private const string ImplicitBodyNotProvidedExceptionMessage = @"Implicit body inferred for parameter ""{0}"" but no body was provided. Did you mean to use a Service instead?";
12121223

@@ -1218,18 +1229,19 @@ public static void RequestBodyIOException(HttpContext httpContext, IOException e
12181229
[LoggerMessage(1, LogLevel.Debug, "Reading the request body failed with an IOException.", EventName = "RequestBodyIOException")]
12191230
private static partial void RequestBodyIOException(ILogger logger, IOException exception);
12201231

1221-
public static void RequestBodyInvalidDataException(HttpContext httpContext, InvalidDataException exception, bool shouldThrow)
1232+
public static void InvalidJsonRequestBody(HttpContext httpContext, string parameterTypeName, string parameterName, Exception exception, bool shouldThrow)
12221233
{
12231234
if (shouldThrow)
12241235
{
1225-
throw new BadHttpRequestException(RequestBodyInvalidDataExceptionMessage, exception);
1236+
var message = string.Format(CultureInfo.InvariantCulture, InvalidJsonRequestBodyExceptionMessage, parameterTypeName, parameterName);
1237+
throw new BadHttpRequestException(message, exception);
12261238
}
12271239

1228-
RequestBodyInvalidDataException(GetLogger(httpContext), exception);
1240+
InvalidJsonRequestBody(GetLogger(httpContext), parameterTypeName, parameterName, exception);
12291241
}
12301242

1231-
[LoggerMessage(2, LogLevel.Debug, RequestBodyInvalidDataExceptionMessage, EventName = "RequestBodyInvalidDataException")]
1232-
private static partial void RequestBodyInvalidDataException(ILogger logger, InvalidDataException exception);
1243+
[LoggerMessage(2, LogLevel.Debug, InvalidJsonRequestBodyMessage, EventName = "InvalidJsonRequestBody")]
1244+
private static partial void InvalidJsonRequestBody(ILogger logger, string parameterType, string parameterName, Exception exception);
12331245

12341246
public static void ParameterBindingFailed(HttpContext httpContext, string parameterTypeName, string parameterName, string sourceValue, bool shouldThrow)
12351247
{
@@ -1259,16 +1271,6 @@ public static void RequiredParameterNotProvided(HttpContext httpContext, string
12591271
[LoggerMessage(4, LogLevel.Debug, RequiredParameterNotProvidedLogMessage, EventName = "RequiredParameterNotProvided")]
12601272
private static partial void RequiredParameterNotProvided(ILogger logger, string parameterType, string parameterName, string source);
12611273

1262-
public static void UnexpectedContentType(HttpContext httpContext, string? contentType, bool shouldThrow)
1263-
{
1264-
if (shouldThrow)
1265-
{
1266-
var message = string.Format(CultureInfo.InvariantCulture, UnexpectedContentTypeExceptionMessage, contentType);
1267-
throw new BadHttpRequestException(message, StatusCodes.Status415UnsupportedMediaType);
1268-
}
1269-
1270-
UnexpectedContentType(GetLogger(httpContext), contentType ?? "(none)");
1271-
}
12721274
public static void ImplicitBodyNotProvided(HttpContext httpContext, string parameterName, bool shouldThrow)
12731275
{
12741276
if (shouldThrow)
@@ -1283,8 +1285,16 @@ public static void ImplicitBodyNotProvided(HttpContext httpContext, string param
12831285
[LoggerMessage(5, LogLevel.Debug, ImplicitBodyNotProvidedLogMessage, EventName = "ImplicitBodyNotProvided")]
12841286
private static partial void ImplicitBodyNotProvided(ILogger logger, string parameterName);
12851287

1286-
public static void UnexpectedContentType(HttpContext httpContext, string? contentType)
1287-
=> UnexpectedContentType(GetLogger(httpContext), contentType ?? "(none)");
1288+
public static void UnexpectedContentType(HttpContext httpContext, string? contentType, bool shouldThrow)
1289+
{
1290+
if (shouldThrow)
1291+
{
1292+
var message = string.Format(CultureInfo.InvariantCulture, UnexpectedContentTypeExceptionMessage, contentType);
1293+
throw new BadHttpRequestException(message, StatusCodes.Status415UnsupportedMediaType);
1294+
}
1295+
1296+
UnexpectedContentType(GetLogger(httpContext), contentType ?? "(none)");
1297+
}
12881298

12891299
[LoggerMessage(6, LogLevel.Debug, UnexpectedContentTypeLogMessage, EventName = "UnexpectedContentType")]
12901300
private static partial void UnexpectedContentType(ILogger logger, string contentType);

0 commit comments

Comments
 (0)