Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
lineNumber);
}
""");
}
}

return code.ToString();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ private static Task ExecuteObjectResult(object? obj, HttpContext httpContext)
}
return (false, default);
}

private static StringValues ResolveFromRouteOrQuery(HttpContext httpContext, string parameterName, IEnumerable<string>? routeParameterNames)
{
return routeParameterNames?.Contains(parameterName, StringComparer.OrdinalIgnoreCase) == true
? new StringValues(httpContext.Request.RouteValues[$"{parameterName}"]?.ToString())
: httpContext.Request.Query[$"{parameterName}"];
}
}

{{GeneratedCodeAttribute}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Linq;
using System.Text;

namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel.Emitters;
Expand All @@ -21,8 +22,14 @@ internal static string EmitParameterPreparation(this Endpoint endpoint)
Source: EndpointParameterSource.SpecialType
} => parameter.EmitSpecialParameterPreparation(),
{
Source: EndpointParameterSource.Query,
} => parameter.EmitQueryParameterPreparation(),
Source: EndpointParameterSource.Query or EndpointParameterSource.Header,
} => parameter.EmitQueryOrHeaderParameterPreparation(),
{
Source: EndpointParameterSource.Route,
} => parameter.EmitRouteParameterPreparation(),
{
Source: EndpointParameterSource.RouteOrQuery
} => parameter.EmitRouteOrQueryParameterPreparation(),
{
Source: EndpointParameterSource.JsonBody
} => parameter.EmitJsonBodyParameterPreparationString(),
Expand All @@ -45,4 +52,6 @@ internal static string EmitParameterPreparation(this Endpoint endpoint)

return parameterPreparationBuilder.ToString();
}

public static string EmitArgumentList(this Endpoint endpoint) => string.Join(", ", endpoint.Parameters.Select(p => p.EmitArgument()));
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Text;

namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel.Emitters;
Expand All @@ -9,22 +10,22 @@ internal static class EndpointParameterEmitter
internal static string EmitSpecialParameterPreparation(this EndpointParameter endpointParameter)
{
return $"""
var {endpointParameter.Name}_local = {endpointParameter.AssigningCode};
var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.AssigningCode};
""";
}

internal static string EmitQueryParameterPreparation(this EndpointParameter endpointParameter)
internal static string EmitQueryOrHeaderParameterPreparation(this EndpointParameter endpointParameter)
{
var builder = new StringBuilder();

// Preamble for diagnostics purposes.
builder.AppendLine($"""
{endpointParameter.EmitParameterDiagnosticComment()}
""");

// Grab raw input from HttpContext.
var assigningCode = endpointParameter.Source is EndpointParameterSource.Header
? $"httpContext.Request.Headers[\"{endpointParameter.Name}\"]"
: $"httpContext.Request.Query[\"{endpointParameter.Name}\"]";
builder.AppendLine($$"""
var {{endpointParameter.Name}}_raw = {{endpointParameter.AssigningCode}};
var {{endpointParameter.EmitAssigningCodeResult()}} = {{assigningCode}};
""");

// If we are not optional, then at this point we can just assign the string value to the handler argument,
Expand All @@ -34,35 +35,100 @@ internal static string EmitQueryParameterPreparation(this EndpointParameter endp
if (endpointParameter.IsOptional)
{
builder.AppendLine($$"""
var {{endpointParameter.HandlerArgument}} = {{endpointParameter.Name}}_raw.Count > 0 ? {{endpointParameter.Name}}_raw.ToString() : null;
var {{endpointParameter.EmitHandlerArgument()}} = {{endpointParameter.EmitAssigningCodeResult()}}.Count > 0 ? {{endpointParameter.EmitAssigningCodeResult()}}.ToString() : null;
""");
}
else
{
builder.AppendLine($$"""
if (StringValues.IsNullOrEmpty({{endpointParameter.Name}}_raw))
if (StringValues.IsNullOrEmpty({{endpointParameter.EmitAssigningCodeResult()}}))
{
wasParamCheckFailure = true;
}
var {{endpointParameter.HandlerArgument}} = {{endpointParameter.Name}}_raw.ToString();
var {{endpointParameter.EmitHandlerArgument()}} = {{endpointParameter.EmitAssigningCodeResult()}}.ToString();
""");
}

return builder.ToString();
}

internal static string EmitJsonBodyParameterPreparationString(this EndpointParameter endpointParameter)
internal static string EmitRouteParameterPreparation(this EndpointParameter endpointParameter)
{
var builder = new StringBuilder();
builder.AppendLine($"""
{endpointParameter.EmitParameterDiagnosticComment()}
""");

// Preamble for diagnostics purposes.
// Throw an exception of if the route parameter name that was specific in the `FromRoute`
// attribute or in the parameter name does not appear in the actual route.
builder.AppendLine($$"""
if (options?.RouteParameterNames?.Contains("{{endpointParameter.Name}}", StringComparer.OrdinalIgnoreCase) != true)
{
throw new InvalidOperationException($"'{{endpointParameter.Name}}' is not a route parameter.");
}
""");

var assigningCode = $"httpContext.Request.RouteValues[\"{endpointParameter.Name}\"]?.ToString()";
builder.AppendLine($$"""
var {{endpointParameter.EmitAssigningCodeResult()}} = {{assigningCode}};
""");

if (!endpointParameter.IsOptional)
{
builder.AppendLine($$"""
if ({{endpointParameter.EmitAssigningCodeResult()}} == null)
{
wasParamCheckFailure = true;
}
""");
}
builder.AppendLine($"""
var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()};
""");

return builder.ToString();
}

internal static string EmitRouteOrQueryParameterPreparation(this EndpointParameter endpointParameter)
{
var builder = new StringBuilder();
builder.AppendLine($"""
{endpointParameter.EmitParameterDiagnosticComment()}
""");

// Grab raw input from HttpContext.
var assigningCode = $"GeneratedRouteBuilderExtensionsCore.ResolveFromRouteOrQuery(httpContext, \"{endpointParameter.Name}\", options?.RouteParameterNames)";

builder.AppendLine($$"""
var (isSuccessful, {{endpointParameter.Name}}_local) = {{endpointParameter.AssigningCode}};
var {{endpointParameter.EmitAssigningCodeResult()}} = {{assigningCode}};
""");

if (!endpointParameter.IsOptional)
{
builder.AppendLine($$"""
if ({{endpointParameter.EmitAssigningCodeResult()}} is StringValues { Count: 0 })
{
wasParamCheckFailure = true;
}
""");
}

builder.AppendLine($"""
var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()};
""");

return builder.ToString();
}

internal static string EmitJsonBodyParameterPreparationString(this EndpointParameter endpointParameter)
{
var builder = new StringBuilder();
builder.AppendLine($"""
{endpointParameter.EmitParameterDiagnosticComment()}
""");

var assigningCode = $"await GeneratedRouteBuilderExtensionsCore.TryResolveBody<{endpointParameter.Type}>(httpContext, {(endpointParameter.IsOptional ? "true" : "false")})";
builder.AppendLine($$"""
var (isSuccessful, {{endpointParameter.EmitHandlerArgument()}}) = {{assigningCode}};
""");

// If binding from the JSON body fails, we exit early. Don't
Expand All @@ -87,15 +153,31 @@ internal static string EmitServiceParameterPreparation(this EndpointParameter en
{endpointParameter.EmitParameterDiagnosticComment()}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit on existing code)

Does this need to be wrapped in a """ string? Why can't it just be:

builder.AppendLine(endpointParameter.EmitParameterDiagnosticComment());

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation! 😢

But see #46845 for some goodies.

""");

var assigningCode = endpointParameter.IsOptional ?
$"httpContext.RequestServices.GetService<{endpointParameter.Type}>();" :
$"httpContext.RequestServices.GetRequiredService<{endpointParameter.Type}>()";

// Requiredness checks for services are handled by the distinction
// between GetRequiredService and GetService in the AssigningCode.
builder.AppendLine($$"""
var {{endpointParameter.HandlerArgument}} = {{endpointParameter.AssigningCode}};
var {{endpointParameter.EmitHandlerArgument()}} = {{assigningCode}};
""");

return builder.ToString();
}

private static string EmitParameterDiagnosticComment(this EndpointParameter endpointParameter) =>
$"// Endpoint Parameter: {endpointParameter.Name} (Type = {endpointParameter.Type}, IsOptional = {endpointParameter.IsOptional}, Source = {endpointParameter.Source})";

private static string EmitHandlerArgument(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_local";
private static string EmitAssigningCodeResult(this EndpointParameter endpointParameter) => $"{endpointParameter.Name}_raw";

public static string EmitArgument(this EndpointParameter endpointParameter) => endpointParameter.Source switch
{
EndpointParameterSource.JsonBody or EndpointParameterSource.Route or EndpointParameterSource.RouteOrQuery => endpointParameter.IsOptional
? endpointParameter.EmitHandlerArgument()
: $"{endpointParameter.EmitHandlerArgument()}!",
EndpointParameterSource.Unknown => throw new Exception("Unreachable!"),
_ => endpointParameter.EmitHandlerArgument()
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel;

internal class Endpoint
{
private string? _argumentListCache;

public Endpoint(IInvocationOperation operation, WellKnownTypes wellKnownTypes)
{
Operation = operation;
Expand Down Expand Up @@ -67,8 +65,6 @@ public Endpoint(IInvocationOperation operation, WellKnownTypes wellKnownTypes)
public string? RoutePattern { get; }
public EndpointResponse? Response { get; }
public EndpointParameter[] Parameters { get; } = Array.Empty<EndpointParameter>();
public string EmitArgumentList() => _argumentListCache ??= string.Join(", ", Parameters.Select(p => p.EmitArgument()));

public List<DiagnosticDescriptor> Diagnostics { get; } = new List<DiagnosticDescriptor>();

public (string File, int LineNumber) Location { get; }
Expand All @@ -91,7 +87,7 @@ public static bool SignatureEquals(Endpoint a, Endpoint b)

for (var i = 0; i < a.Parameters.Length; i++)
{
if (!a.Parameters[i].Equals(b.Parameters[i]))
if (!a.Parameters[i].SignatureEquals(b.Parameters[i]))
{
return false;
}
Expand All @@ -108,7 +104,7 @@ public static int GetSignatureHashCode(Endpoint endpoint)

foreach (var parameter in endpoint.Parameters)
{
hashCode.Add(parameter);
hashCode.Add(parameter.Type, SymbolEqualityComparer.Default);
}

return hashCode.ToHashCode();
Expand Down
Loading