Skip to content

Commit

Permalink
DisableInferBodyFromParameters in RDG. (dotnet#48269)
Browse files Browse the repository at this point in the history
* DisableInferBodyFromParameters in RDG.
  • Loading branch information
mitchdenny authored May 23, 2023
1 parent 6c66253 commit 6c49e7b
Show file tree
Hide file tree
Showing 46 changed files with 2,968 additions and 185 deletions.
9 changes: 6 additions & 3 deletions src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
codeWriter.StartBlock();
codeWriter.WriteLine(@"Debug.Assert(options != null, ""RequestDelegateFactoryOptions not found."");");
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder != null, ""EndpointBuilder not found."");");
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder.ApplicationServices != null, ""ApplicationServices not found."");");
codeWriter.WriteLine(@"Debug.Assert(options.EndpointBuilder.FilterFactories != null, ""FilterFactories not found."");");
codeWriter.WriteLine($"var handler = ({endpoint.EmitHandlerDelegateType(considerOptionality: true)})del;");
codeWriter.WriteLine("EndpointFilterDelegate? filteredInvocation = null;");
if (endpoint.EmitterContext.RequiresLoggingHelper || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.Response?.IsSerializableJsonResponse(out var _) is true)
Expand All @@ -89,7 +91,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
codeWriter.WriteLine("var parameters = del.Method.GetParameters();");
}
codeWriter.WriteLineNoTabs(string.Empty);
codeWriter.WriteLine("if (options?.EndpointBuilder?.FilterFactories.Count > 0)");
codeWriter.WriteLine("if (options.EndpointBuilder.FilterFactories.Count > 0)");
codeWriter.StartBlock();
codeWriter.WriteLine(endpoint.Response?.IsAwaitable == true
? "filteredInvocation = GeneratedRouteBuilderExtensionsCore.BuildFilterDelegate(async ic =>"
Expand Down Expand Up @@ -173,6 +175,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select((endpoints, _) =>
{
var hasJsonBodyOrService = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBodyOrService);
var hasJsonBodyOrQuery = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBodyOrQuery);
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody);
var hasFormBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasFormBody);
var hasRouteOrQuery = endpoints.Any(endpoint => endpoint.EmitterContext.HasRouteOrQuery);
Expand All @@ -196,7 +199,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
codeWriter.WriteLine(RequestDelegateGeneratorSources.WriteToResponseAsyncMethod);
}

if (hasJsonBody || hasJsonBodyOrService)
if (hasJsonBody || hasJsonBodyOrService || hasJsonBodyOrQuery)
{
codeWriter.WriteLine(RequestDelegateGeneratorSources.TryResolveBodyAsyncMethod);
}
Expand Down Expand Up @@ -244,7 +247,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select((endpoints, _) =>
{
var hasFormBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasFormBody);
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService);
var hasJsonBody = endpoints.Any(endpoint => endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.EmitterContext.HasJsonBodyOrQuery);
var hasResponseMetadata = endpoints.Any(endpoint => endpoint.EmitterContext.HasResponseMetadata);
var requiresPropertyAsParameterInfo = endpoints.Any(endpoint => endpoint.EmitterContext.RequiresPropertyAsParameterInfo);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerM
internal sealed class EmitterContext
{
public bool HasJsonBodyOrService { get; set; }
public bool HasJsonBodyOrQuery { get; set; }
public bool HasJsonBody { get; set; }
public bool HasFormBody { get; set; }
public bool HasRouteOrQuery { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ internal static string EmitParameterPreparation(this IEnumerable<EndpointParamet
case EndpointParameterSource.JsonBodyOrService:
parameter.EmitJsonBodyOrServiceParameterPreparationString(parameterPreparationBuilder);
break;
case EndpointParameterSource.JsonBodyOrQuery:
parameter.EmitJsonBodyOrQueryParameterPreparationString(parameterPreparationBuilder);
break;
case EndpointParameterSource.Service:
parameter.EmitServiceParameterPreparation(parameterPreparationBuilder);
break;
Expand Down Expand Up @@ -80,7 +83,7 @@ static void ProcessParameter(EndpointParameter parameter, CodeWriter codeWriter,
{
var parameterName = parameter.SymbolName;
codeWriter.Write($@"var {parameterName}_RouteOrQueryResolver = ");
codeWriter.WriteLine($@"GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(""{parameterName}"", options?.RouteParameterNames);");
codeWriter.WriteLine($@"GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(""{parameterName}"", options.RouteParameterNames);");
endpoint.EmitterContext.HasRouteOrQuery = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,41 @@ internal static void EmitJsonBodyOrServiceParameterPreparationString(this Endpoi
codeWriter.EndBlock();
}

internal static void EmitJsonBodyOrQueryParameterPreparationString(this EndpointParameter endpointParameter, CodeWriter codeWriter)
{
// Preamble for diagnostics purposes.
codeWriter.WriteLine(endpointParameter.EmitParameterDiagnosticComment());

// Declare handler variable up front.
codeWriter.WriteLine($"{endpointParameter.Type.ToDisplayString(EmitterConstants.DisplayFormat)} {endpointParameter.EmitHandlerArgument()} = null!;");
codeWriter.WriteLine("if (options.DisableInferBodyFromParameters)");
codeWriter.StartBlock();
codeWriter.WriteLine($"""var {endpointParameter.EmitAssigningCodeResult()} = httpContext.Request.Query["{endpointParameter.LookupName}"];""");
codeWriter.WriteLine($"""{endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()}!;""");
codeWriter.EndBlock();
codeWriter.WriteLine("else");
codeWriter.StartBlock();

// This code is adapted from the EmitJsonBodyParameterPreparationString method with some modifications
// because the handler argument is emitted before the containing if block (which makes it awkward to
// simply reuse that emission code) - opted for duplication (with tweaks) over complexity.
var shortParameterTypeName = endpointParameter.Type.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat);
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)})";
var resolveBodyResult = $"{endpointParameter.SymbolName}_resolveBodyResult";
codeWriter.WriteLine($"var {resolveBodyResult} = {assigningCode};");
codeWriter.WriteLine($"{endpointParameter.EmitHandlerArgument()} = {resolveBodyResult}.Item2!;");

// If binding from the JSON body fails, we exit early. Don't
// set the status code here because assume it has been set by the
// TryResolveBody method.
codeWriter.WriteLine($"if (!{resolveBodyResult}.Item1)");
codeWriter.StartBlock();
codeWriter.WriteLine("return;");
codeWriter.EndBlock();

codeWriter.EndBlock();
}

internal static void EmitBindAsyncPreparation(this EndpointParameter endpointParameter, CodeWriter codeWriter)
{
var unwrappedType = endpointParameter.Type.UnwrapTypeSymbol(unwrapNullable: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,12 @@ Type is not INamedTypeSymbol namedTypeSymbol ||
{
Source = EndpointParameterSource.RouteOrQuery;
}
else if (ShouldDisableInferredBodyParameters(endpoint.HttpMethod) && IsArray && ElementType.SpecialType == SpecialType.System_String)
else if (IsArray && ElementType.SpecialType == SpecialType.System_String)
{
Source = EndpointParameterSource.Query;
endpoint.IsAwaitable = true;
Source = EndpointParameterSource.JsonBodyOrQuery;
}
else if (ShouldDisableInferredBodyParameters(endpoint.HttpMethod) && SymbolEqualityComparer.Default.Equals(Type, wellKnownTypes.Get(WellKnownType.Microsoft_Extensions_Primitives_StringValues)))
else if (SymbolEqualityComparer.Default.Equals(Type, wellKnownTypes.Get(WellKnownType.Microsoft_Extensions_Primitives_StringValues)))
{
Source = EndpointParameterSource.Query;
IsStringValues = true;
Expand All @@ -227,6 +228,7 @@ Type is not INamedTypeSymbol namedTypeSymbol ||
endpoint.EmitterContext.HasFormBody |= Source == EndpointParameterSource.FormBody;
endpoint.EmitterContext.HasJsonBody |= Source == EndpointParameterSource.JsonBody;
endpoint.EmitterContext.HasJsonBodyOrService |= Source == EndpointParameterSource.JsonBodyOrService;
endpoint.EmitterContext.HasJsonBodyOrQuery |= Source == EndpointParameterSource.JsonBodyOrQuery;
}

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

private static bool ShouldDisableInferredBodyParameters(string httpMethod)
{
switch (httpMethod)
{
case "MapPut" or "MapPatch" or "MapPost":
return false;
default:
return true;
}
}

public ITypeSymbol Type { get; }
public ITypeSymbol ElementType { get; }
public bool IsEndpointMetadataProvider { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ internal enum EndpointParameterSource
// Used to track that the parameter is annotated with `AsParameters` and
// can explode to multiple parameters
AsParameters,
JsonBodyOrQuery,
}
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ public static void EmitJsonAcceptsMetadata(this Endpoint endpoint, CodeWriter co
explicitBodyParameter = parameter;
break;
}
else if (parameter.Source == EndpointParameterSource.JsonBodyOrService)
else if (parameter.Source == EndpointParameterSource.JsonBodyOrService || parameter.Source == EndpointParameterSource.JsonBodyOrQuery)
{
potentialImplicitBodyParameters.Add(parameter);
}
Expand Down Expand Up @@ -311,7 +311,7 @@ public static void EmitJsonAcceptsMetadata(this Endpoint endpoint, CodeWriter co

public static void EmitAcceptsMetadata(this Endpoint endpoint, CodeWriter codeWriter)
{
var hasJsonBody = endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService;
var hasJsonBody = endpoint.EmitterContext.HasJsonBody || endpoint.EmitterContext.HasJsonBodyOrService || endpoint.EmitterContext.HasJsonBodyOrQuery;

if (endpoint.EmitterContext.HasFormBody)
{
Expand Down
Loading

0 comments on commit 6c49e7b

Please sign in to comment.