Skip to content

Commit 6c49e7b

Browse files
authored
DisableInferBodyFromParameters in RDG. (#48269)
* DisableInferBodyFromParameters in RDG.
1 parent 6c66253 commit 6c49e7b

File tree

46 files changed

+2968
-185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2968
-185
lines changed

src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7474
codeWriter.StartBlock();
7575
codeWriter.WriteLine(@"Debug.Assert(options != null, ""RequestDelegateFactoryOptions not found."");");
7676
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder != null, ""EndpointBuilder not found."");");
77+
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder.ApplicationServices != null, ""ApplicationServices not found."");");
78+
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder.FilterFactories != null, ""FilterFactories not found."");");
7779
codeWriter.WriteLine($"var handler = ({endpoint.EmitHandlerDelegateType(considerOptionality: true)})del;");
7880
codeWriter.WriteLine("EndpointFilterDelegate? filteredInvocation = null;");
7981
if (endpoint.EmitterContext.RequiresLoggingHelper || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.Response?.IsSerializableJsonResponse(out var _) is true)
@@ -89,7 +91,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8991
codeWriter.WriteLine("var parameters = del.Method.GetParameters();");
9092
}
9193
codeWriter.WriteLineNoTabs(string.Empty);
92-
codeWriter.WriteLine("if (options?.EndpointBuilder?.FilterFactories.Count > 0)");
94+
codeWriter.WriteLine("if (options.EndpointBuilder.FilterFactories.Count > 0)");
9395
codeWriter.StartBlock();
9496
codeWriter.WriteLine(endpoint.Response?.IsAwaitable == true
9597
? "filteredInvocation = GeneratedRouteBuilderExtensionsCore.BuildFilterDelegate(async ic =>"
@@ -173,6 +175,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
173175
.Select((endpoints, _) =>
174176
{
175177
var hasJsonBodyOrService = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBodyOrService);
178+
var hasJsonBodyOrQuery = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBodyOrQuery);
176179
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody);
177180
var hasFormBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasFormBody);
178181
var hasRouteOrQuery = endpoints.Any(endpoint => endpoint.EmitterContext.HasRouteOrQuery);
@@ -196,7 +199,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
196199
codeWriter.WriteLine(RequestDelegateGeneratorSources.WriteToResponseAsyncMethod);
197200
}
198201

199-
if (hasJsonBody || hasJsonBodyOrService)
202+
if (hasJsonBody || hasJsonBodyOrService || hasJsonBodyOrQuery)
200203
{
201204
codeWriter.WriteLine(RequestDelegateGeneratorSources.TryResolveBodyAsyncMethod);
202205
}
@@ -244,7 +247,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
244247
.Select((endpoints, _) =>
245248
{
246249
var hasFormBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasFormBody);
247-
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService);
250+
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.EmitterContext.HasJsonBodyOrQuery);
248251
var hasResponseMetadata = endpoints.Any(endpoint => endpoint.EmitterContext.HasResponseMetadata);
249252
var requiresPropertyAsParameterInfo = endpoints.Any(endpoint => endpoint.EmitterContext.RequiresPropertyAsParameterInfo);
250253

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerM
55
internal sealed class EmitterContext
66
{
77
public bool HasJsonBodyOrService { get; set; }
8+
public bool HasJsonBodyOrQuery { get; set; }
89
public bool HasJsonBody { get; set; }
910
public bool HasFormBody { get; set; }
1011
public bool HasRouteOrQuery { get; set; }

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ internal static string EmitParameterPreparation(this IEnumerable<EndpointParamet
4848
case EndpointParameterSource.JsonBodyOrService:
4949
parameter.EmitJsonBodyOrServiceParameterPreparationString(parameterPreparationBuilder);
5050
break;
51+
case EndpointParameterSource.JsonBodyOrQuery:
52+
parameter.EmitJsonBodyOrQueryParameterPreparationString(parameterPreparationBuilder);
53+
break;
5154
case EndpointParameterSource.Service:
5255
parameter.EmitServiceParameterPreparation(parameterPreparationBuilder);
5356
break;
@@ -80,7 +83,7 @@ static void ProcessParameter(EndpointParameter parameter, CodeWriter codeWriter,
8083
{
8184
var parameterName = parameter.SymbolName;
8285
codeWriter.Write($@"var {parameterName}_RouteOrQueryResolver = ");
83-
codeWriter.WriteLine($@"GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(""{parameterName}"", options?.RouteParameterNames);");
86+
codeWriter.WriteLine($@"GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(""{parameterName}"", options.RouteParameterNames);");
8487
endpoint.EmitterContext.HasRouteOrQuery = true;
8588
}
8689
}

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,41 @@ internal static void EmitJsonBodyOrServiceParameterPreparationString(this Endpoi
225225
codeWriter.EndBlock();
226226
}
227227

228+
internal static void EmitJsonBodyOrQueryParameterPreparationString(this EndpointParameter endpointParameter, CodeWriter codeWriter)
229+
{
230+
// Preamble for diagnostics purposes.
231+
codeWriter.WriteLine(endpointParameter.EmitParameterDiagnosticComment());
232+
233+
// Declare handler variable up front.
234+
codeWriter.WriteLine($"{endpointParameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)} {endpointParameter.EmitHandlerArgument()} = null!;");
235+
codeWriter.WriteLine("if (options.DisableInferBodyFromParameters)");
236+
codeWriter.StartBlock();
237+
codeWriter.WriteLine($"""var {endpointParameter.EmitAssigningCodeResult()} = httpContext.Request.Query["{endpointParameter.LookupName}"];""");
238+
codeWriter.WriteLine($"""{endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()}!;""");
239+
codeWriter.EndBlock();
240+
codeWriter.WriteLine("else");
241+
codeWriter.StartBlock();
242+
243+
// This code is adapted from the EmitJsonBodyParameterPreparationString method with some modifications
244+
// because the handler argument is emitted before the containing if block (which makes it awkward to
245+
// simply reuse that emission code) - opted for duplication (with tweaks) over complexity.
246+
var shortParameterTypeName = endpointParameter.Type.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat);
247+
var assigningCode = $"await GeneratedRouteBuilderExtensionsCore.TryResolveBodyAsync<{endpointParameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)}>(httpContext, logOrThrowExceptionHelper, {(endpointParameter.IsOptional ? "true" : "false")}, {SymbolDisplay.FormatLiteral(shortParameterTypeName, true)}, {SymbolDisplay.FormatLiteral(endpointParameter.SymbolName, true)})";
248+
var resolveBodyResult = $"{endpointParameter.SymbolName}_resolveBodyResult";
249+
codeWriter.WriteLine($"var {resolveBodyResult} = {assigningCode};");
250+
codeWriter.WriteLine($"{endpointParameter.EmitHandlerArgument()} = {resolveBodyResult}.Item2!;");
251+
252+
// If binding from the JSON body fails, we exit early. Don't
253+
// set the status code here because assume it has been set by the
254+
// TryResolveBody method.
255+
codeWriter.WriteLine($"if (!{resolveBodyResult}.Item1)");
256+
codeWriter.StartBlock();
257+
codeWriter.WriteLine("return;");
258+
codeWriter.EndBlock();
259+
260+
codeWriter.EndBlock();
261+
}
262+
228263
internal static void EmitBindAsyncPreparation(this EndpointParameter endpointParameter, CodeWriter codeWriter)
229264
{
230265
var unwrappedType = endpointParameter.Type.UnwrapTypeSymbol(unwrapNullable: true);

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,12 @@ Type is not INamedTypeSymbol namedTypeSymbol ||
201201
{
202202
Source = EndpointParameterSource.RouteOrQuery;
203203
}
204-
else if (ShouldDisableInferredBodyParameters(endpoint.HttpMethod) && IsArray && ElementType.SpecialType == SpecialType.System_String)
204+
else if (IsArray && ElementType.SpecialType == SpecialType.System_String)
205205
{
206-
Source = EndpointParameterSource.Query;
206+
endpoint.IsAwaitable = true;
207+
Source = EndpointParameterSource.JsonBodyOrQuery;
207208
}
208-
else if (ShouldDisableInferredBodyParameters(endpoint.HttpMethod) && SymbolEqualityComparer.Default.Equals(Type, wellKnownTypes.Get(WellKnownType.Microsoft_Extensions_Primitives_StringValues)))
209+
else if (SymbolEqualityComparer.Default.Equals(Type, wellKnownTypes.Get(WellKnownType.Microsoft_Extensions_Primitives_StringValues)))
209210
{
210211
Source = EndpointParameterSource.Query;
211212
IsStringValues = true;
@@ -227,6 +228,7 @@ Type is not INamedTypeSymbol namedTypeSymbol ||
227228
endpoint.EmitterContext.HasFormBody |= Source == EndpointParameterSource.FormBody;
228229
endpoint.EmitterContext.HasJsonBody |= Source == EndpointParameterSource.JsonBody;
229230
endpoint.EmitterContext.HasJsonBodyOrService |= Source == EndpointParameterSource.JsonBodyOrService;
231+
endpoint.EmitterContext.HasJsonBodyOrQuery |= Source == EndpointParameterSource.JsonBodyOrQuery;
230232
}
231233

232234
private static bool ImplementsIEndpointMetadataProvider(ITypeSymbol type, WellKnownTypes wellKnownTypes)
@@ -235,17 +237,6 @@ private static bool ImplementsIEndpointMetadataProvider(ITypeSymbol type, WellKn
235237
private static bool ImplementsIEndpointParameterMetadataProvider(ITypeSymbol type, WellKnownTypes wellKnownTypes)
236238
=> type.Implements(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IEndpointParameterMetadataProvider));
237239

238-
private static bool ShouldDisableInferredBodyParameters(string httpMethod)
239-
{
240-
switch (httpMethod)
241-
{
242-
case "MapPut" or "MapPatch" or "MapPost":
243-
return false;
244-
default:
245-
return true;
246-
}
247-
}
248-
249240
public ITypeSymbol Type { get; }
250241
public ITypeSymbol ElementType { get; }
251242
public bool IsEndpointMetadataProvider { get; }

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameterSource.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ internal enum EndpointParameterSource
2323
// Used to track that the parameter is annotated with `AsParameters` and
2424
// can explode to multiple parameters
2525
AsParameters,
26+
JsonBodyOrQuery,
2627
}

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public static void EmitJsonAcceptsMetadata(this Endpoint endpoint, CodeWriter co
271271
explicitBodyParameter = parameter;
272272
break;
273273
}
274-
else if (parameter.Source == EndpointParameterSource.JsonBodyOrService)
274+
else if (parameter.Source == EndpointParameterSource.JsonBodyOrService || parameter.Source == EndpointParameterSource.JsonBodyOrQuery)
275275
{
276276
potentialImplicitBodyParameters.Add(parameter);
277277
}
@@ -311,7 +311,7 @@ public static void EmitJsonAcceptsMetadata(this Endpoint endpoint, CodeWriter co
311311

312312
public static void EmitAcceptsMetadata(this Endpoint endpoint, CodeWriter codeWriter)
313313
{
314-
var hasJsonBody = endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService;
314+
var hasJsonBody = endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.EmitterContext.HasJsonBodyOrQuery;
315315

316316
if (endpoint.EmitterContext.HasFormBody)
317317
{

0 commit comments

Comments
 (0)