diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs
index ef2bef8f2240..8dfd0c7e93e4 100644
--- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs
+++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs
@@ -161,10 +161,10 @@ internal static class DiagnosticDescriptors
isEnabledByDefault: true,
helpLinkUri: "https://aka.ms/aspnet/analyzers");
- internal static readonly DiagnosticDescriptor RouteParameterComplexTypeIsNotParsableOrBindable = new(
+ internal static readonly DiagnosticDescriptor RouteParameterComplexTypeIsNotParsable = new(
"ASP0020",
"Complex types referenced by route parameters must be parsable",
- "Parameter '{0}' of type {1} should define a bool TryParse(string, IFormatProvider, out {1}) method, or implement IParsable<{1}>, or define a ValueTask<{1}> BindAsync(HttpContext), or implement IBindableFromHttpContext<{1}>.",
+ "Parameter '{0}' of type {1} should define a bool TryParse(string, IFormatProvider, out {1}) method, or implement IParsable<{1}>.",
"Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj
index e68fcbf8ccac..0e632da24044 100644
--- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj
+++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj
@@ -27,10 +27,7 @@
-
-
-
-
+
diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/DisallowNonParsableComplexTypesOnParameters.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/DisallowNonParsableComplexTypesOnParameters.cs
index ce65f2d1e42f..1d5f8550a1a5 100644
--- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/DisallowNonParsableComplexTypesOnParameters.cs
+++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/DisallowNonParsableComplexTypesOnParameters.cs
@@ -68,14 +68,11 @@ private static void DisallowNonParsableComplexTypesOnParameters(
if (IsRouteParameter(routeUsage, handlerDelegateParameter))
{
var parsability = ParsabilityHelper.GetParsability(parameterTypeSymbol, wellKnownTypes);
- var bindability = ParsabilityHelper.GetBindability(parameterTypeSymbol, wellKnownTypes);
- if (!(parsability == Parsability.Parsable || bindability == Bindability.Bindable))
+ if (parsability != Parsability.Parsable)
{
- var descriptor = SelectDescriptor(parsability, bindability);
-
context.ReportDiagnostic(Diagnostic.Create(
- descriptor,
+ DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable,
location,
handlerDelegateParameter.Name,
parameterTypeSymbol.Name
@@ -103,10 +100,8 @@ static bool ReportFromAttributeDiagnostic(OperationAnalysisContext context, Well
var parsability = ParsabilityHelper.GetParsability(parameterTypeSymbol, wellKnownTypes);
if (parameter.HasAttributeImplementingInterface(fromMetadataInterfaceTypeSymbol) && parsability != Parsability.Parsable)
{
- var descriptor = SelectDescriptor(parsability, Bindability.NotBindable);
-
context.ReportDiagnostic(Diagnostic.Create(
- descriptor,
+ DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable,
location,
parameter.Name,
parameterTypeSymbol.Name
@@ -140,16 +135,5 @@ static bool ReportFromAttributeDiagnostic(OperationAnalysisContext context, Well
return parameterTypeSymbol;
}
-
- static DiagnosticDescriptor SelectDescriptor(Parsability parsability, Bindability bindability)
- {
- // This abomination is used to take the parsability and bindability and together figure
- // out what the most optimal diagnostic message is to give to our plucky user.
- return (parsability, bindability) switch
- {
- { parsability: Parsability.NotParsable, bindability: Bindability.InvalidReturnType } => DiagnosticDescriptors.BindAsyncSignatureMustReturnValueTaskOfT,
- _ => DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsableOrBindable
- };
- }
}
}
diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/RouteHandlerAnalyzer.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/RouteHandlerAnalyzer.cs
index c5dd2f0a9d8c..274bf3d4d4ce 100644
--- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/RouteHandlerAnalyzer.cs
+++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteHandlers/RouteHandlerAnalyzer.cs
@@ -25,7 +25,7 @@ public partial class RouteHandlerAnalyzer : DiagnosticAnalyzer
DiagnosticDescriptors.DoNotReturnActionResultsFromRouteHandlers,
DiagnosticDescriptors.DetectMisplacedLambdaAttribute,
DiagnosticDescriptors.DetectMismatchedParameterOptionality,
- DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsableOrBindable,
+ DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable,
DiagnosticDescriptors.BindAsyncSignatureMustReturnValueTaskOfT,
DiagnosticDescriptors.AmbiguousRouteHandlerRoute,
DiagnosticDescriptors.AtMostOneFromBodyAttribute
diff --git a/src/Framework/AspNetCoreAnalyzers/test/RouteHandlers/DisallowNonParsableComplexTypesOnParametersTest.cs b/src/Framework/AspNetCoreAnalyzers/test/RouteHandlers/DisallowNonParsableComplexTypesOnParametersTest.cs
index a4bffcbc3a0f..aaa80f6db2c1 100644
--- a/src/Framework/AspNetCoreAnalyzers/test/RouteHandlers/DisallowNonParsableComplexTypesOnParametersTest.cs
+++ b/src/Framework/AspNetCoreAnalyzers/test/RouteHandlers/DisallowNonParsableComplexTypesOnParametersTest.cs
@@ -195,7 +195,7 @@ public class Customer
}
""";
- var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsableOrBindable)
+ var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable)
.WithArguments("customer", "Customer")
.WithLocation(0);
@@ -218,7 +218,7 @@ public class Customer
}
""";
- var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsableOrBindable)
+ var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable)
.WithArguments("customer", "Customer")
.WithLocation(0);
@@ -289,7 +289,7 @@ public static bool TryParse(string s, IFormatProvider provider, out Customer res
}
[Fact]
- public async Task Route_Parameter_withBindAsyncMethodThatReturnsTask_of_T_Fails()
+ public async Task Route_Parameter_withBindAsyncMethod_Fails()
{
// Arrange
var source = $$"""
@@ -301,14 +301,14 @@ public async Task Route_Parameter_withBindAsyncMethodThatReturnsTask_of_T_Fails(
public class Customer
{
- public async static Task BindAsync(HttpContext context)
+ public async static ValueTask BindAsync(HttpContext context)
{
return new Customer();
}
}
""";
- var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.BindAsyncSignatureMustReturnValueTaskOfT)
+ var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable)
.WithArguments("customer", "Customer")
.WithLocation(0);
@@ -422,7 +422,7 @@ public static bool TryParse(string s, IFormatProvider provider, out Customer res
}
[Fact]
- public async Task Route_Parameter_withHttpContextBindableComplexType_viaImplicitIBindableFromHttp_Works()
+ public async Task Route_Parameter_withHttpContextBindableComplexType_viaImplicitIBindableFromHttp_Fails()
{
// Arrange
var source = $$"""
@@ -433,7 +433,7 @@ public async Task Route_Parameter_withHttpContextBindableComplexType_viaImplicit
using Microsoft.AspNetCore.Http;
var webApp = WebApplication.Create();
-webApp.MapGet("/customers/{customer}", (Customer customer) => {});
+webApp.MapGet("/customers/{customer}", ({|#0:Customer customer|}) => {});
public class Customer : IBindableFromHttpContext
{
@@ -444,12 +444,16 @@ public class Customer : IBindableFromHttpContext
}
""";
+ var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable)
+ .WithArguments("customer", "Customer")
+ .WithLocation(0);
+
// Act
- await VerifyCS.VerifyAnalyzerAsync(source);
+ await VerifyCS.VerifyAnalyzerAsync(source, expectedDiagnostic);
}
[Fact]
- public async Task Route_Parameter_withHttpContextBindableComplexType_viaExplicitIBindableFromHttp_Works()
+ public async Task Route_Parameter_withHttpContextBindableComplexType_viaExplicitIBindableFromHttp_Fails()
{
// Arrange
var source = $$"""
@@ -460,7 +464,7 @@ public async Task Route_Parameter_withHttpContextBindableComplexType_viaExplicit
using Microsoft.AspNetCore.Http;
var webApp = WebApplication.Create();
-webApp.MapGet("/customers/{customer}", (Customer customer) => {});
+webApp.MapGet("/customers/{customer}", ({|#0:Customer customer|}) => {});
public class Customer : IBindableFromHttpContext
{
@@ -471,8 +475,12 @@ public class Customer : IBindableFromHttpContext
}
""";
+ var expectedDiagnostic = new DiagnosticResult(DiagnosticDescriptors.RouteParameterComplexTypeIsNotParsable)
+ .WithArguments("customer", "Customer")
+ .WithLocation(0);
+
// Act
- await VerifyCS.VerifyAnalyzerAsync(source);
+ await VerifyCS.VerifyAnalyzerAsync(source, expectedDiagnostic);
}
[Fact]
diff --git a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.Generators.csproj b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.Generators.csproj
index 8b051b325eb1..f339d4fc2351 100644
--- a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.Generators.csproj
+++ b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.Generators.csproj
@@ -24,10 +24,7 @@
-
-
-
-
+
diff --git a/src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs b/src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
index 13d303d40c3b..ebb981855057 100644
--- a/src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
+++ b/src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
@@ -81,6 +81,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
codeWriter.WriteLine("EndpointFilterDelegate? filteredInvocation = null;");
endpoint.EmitRouteOrQueryResolver(codeWriter);
endpoint.EmitJsonPreparation(codeWriter);
+ if (endpoint.NeedsParameterArray)
+ {
+ codeWriter.WriteLine("var parameters = del.Method.GetParameters();");
+ }
codeWriter.WriteLineNoTabs(string.Empty);
codeWriter.WriteLine("if (options?.EndpointBuilder?.FilterFactories.Count > 0)");
codeWriter.StartBlock();
diff --git a/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs b/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs
index 0fd4b4162192..b8bcc470c8dd 100644
--- a/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs
+++ b/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs
@@ -158,6 +158,12 @@ private static Task WriteToResponseAsync(T? value, HttpContext httpContext, J
}
return (false, default);
}
+
+ private static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
+ where T : class, IBindableFromHttpContext
+ {
+ return T.BindAsync(context, parameter);
+ }
}
}
""";
diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs
index 54030a9a8656..3fe38552bd69 100644
--- a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs
+++ b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs
@@ -1,11 +1,9 @@
// 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.Linq;
using System.Globalization;
using System.IO;
-using System.Text;
+using System.Linq;
namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel.Emitters;
internal static class EndpointEmitter
@@ -17,24 +15,28 @@ internal static string EmitParameterPreparation(this Endpoint endpoint, int base
foreach (var parameter in endpoint.Parameters)
{
- switch (parameter)
+ switch (parameter.Source)
{
- case { Source: EndpointParameterSource.SpecialType }:
+ case EndpointParameterSource.SpecialType:
parameter.EmitSpecialParameterPreparation(parameterPreparationBuilder);
break;
- case { Source: EndpointParameterSource.Query or EndpointParameterSource.Header }:
+ case EndpointParameterSource.Query:
+ case EndpointParameterSource.Header:
parameter.EmitQueryOrHeaderParameterPreparation(parameterPreparationBuilder);
break;
- case { Source: EndpointParameterSource.Route }:
+ case EndpointParameterSource.Route:
parameter.EmitRouteParameterPreparation(parameterPreparationBuilder);
break;
- case { Source: EndpointParameterSource.RouteOrQuery }:
+ case EndpointParameterSource.RouteOrQuery:
parameter.EmitRouteOrQueryParameterPreparation(parameterPreparationBuilder);
break;
- case { Source: EndpointParameterSource.JsonBody }:
+ case EndpointParameterSource.BindAsync:
+ parameter.EmitBindAsyncPreparation(parameterPreparationBuilder);
+ break;
+ case EndpointParameterSource.JsonBody:
parameter.EmitJsonBodyParameterPreparationString(parameterPreparationBuilder);
break;
- case { Source: EndpointParameterSource.Service }:
+ case EndpointParameterSource.Service:
parameter.EmitServiceParameterPreparation(parameterPreparationBuilder);
break;
}
diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs
index 89a7bc1622b5..6d841471c314 100644
--- a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs
+++ b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs
@@ -2,10 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Text;
+using Microsoft.AspNetCore.Analyzers.Infrastructure;
+using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel.Emitters;
+
internal static class EndpointParameterEmitter
{
internal static void EmitSpecialParameterPreparation(this EndpointParameter endpointParameter, CodeWriter codeWriter)
@@ -26,7 +28,7 @@ internal static void EmitQueryOrHeaderParameterPreparation(this EndpointParamete
// compiler errors around null handling.
if (endpointParameter.IsOptional)
{
- codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = {endpointParameter.EmitAssigningCodeResult()}.Count > 0 ? {endpointParameter.EmitAssigningCodeResult()}.ToString() : null;");
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = {endpointParameter.EmitAssigningCodeResult()}.Count > 0 ? (string?){endpointParameter.EmitAssigningCodeResult()} : null;");
}
else
{
@@ -34,7 +36,7 @@ internal static void EmitQueryOrHeaderParameterPreparation(this EndpointParamete
codeWriter.StartBlock();
codeWriter.WriteLine("wasParamCheckFailure = true;");
codeWriter.EndBlock();
- codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = {endpointParameter.EmitAssigningCodeResult()}.ToString();");
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = (string?){endpointParameter.EmitAssigningCodeResult()};");
}
endpointParameter.EmitParsingBlock(codeWriter);
@@ -64,7 +66,7 @@ internal static void EmitRouteParameterPreparation(this EndpointParameter endpoi
codeWriter.WriteLine($$"""throw new InvalidOperationException($"'{{endpointParameter.Name}}' is not a route parameter.");""");
codeWriter.EndBlock();
- var assigningCode = $"httpContext.Request.RouteValues[\"{endpointParameter.Name}\"]?.ToString()";
+ var assigningCode = $"(string?)httpContext.Request.RouteValues[\"{endpointParameter.Name}\"]";
codeWriter.WriteLine($"var {endpointParameter.EmitAssigningCodeResult()} = {assigningCode};");
if (!endpointParameter.IsOptional)
@@ -75,7 +77,7 @@ internal static void EmitRouteParameterPreparation(this EndpointParameter endpoi
codeWriter.EndBlock();
}
- codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = {endpointParameter.EmitAssigningCodeResult()}?.ToString();");
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = (string?){endpointParameter.EmitAssigningCodeResult()};");
endpointParameter.EmitParsingBlock(codeWriter);
}
@@ -94,7 +96,8 @@ internal static void EmitRouteOrQueryParameterPreparation(this EndpointParameter
codeWriter.EndBlock();
}
- codeWriter.WriteLine($"var {endpointParameter.EmitHandlerArgument()} = {endpointParameter.EmitAssigningCodeResult()};");
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = (string?){endpointParameter.EmitAssigningCodeResult()};");
+ endpointParameter.EmitParsingBlock(codeWriter);
}
internal static void EmitJsonBodyParameterPreparationString(this EndpointParameter endpointParameter, CodeWriter codeWriter)
@@ -116,6 +119,47 @@ internal static void EmitJsonBodyParameterPreparationString(this EndpointParamet
codeWriter.EndBlock();
}
+ internal static void EmitBindAsyncPreparation(this EndpointParameter endpointParameter, CodeWriter codeWriter)
+ {
+ var unwrappedType = endpointParameter.Type.UnwrapTypeSymbol();
+ var unwrappedTypeString = unwrappedType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+
+ switch (endpointParameter.BindMethod)
+ {
+ case BindabilityMethod.IBindableFromHttpContext:
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = await BindAsync<{unwrappedTypeString}>(httpContext, parameters[{endpointParameter.Ordinal}]);");
+ break;
+ case BindabilityMethod.BindAsyncWithParameter:
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = await {unwrappedTypeString}.BindAsync(httpContext, parameters[{endpointParameter.Ordinal}]);");
+ break;
+ case BindabilityMethod.BindAsync:
+ codeWriter.WriteLine($"var {endpointParameter.EmitTempArgument()} = await {unwrappedTypeString}.BindAsync(httpContext);");
+ break;
+ default:
+ throw new Exception("Unreachable!");
+ }
+
+ // TODO: Generate more compact code if the type is a reference type and/or the BindAsync return nullability matches the handler parameter type.
+ if (endpointParameter.IsOptional)
+ {
+ codeWriter.WriteLine($"var {endpointParameter.EmitHandlerArgument()} = ({unwrappedTypeString}?){endpointParameter.EmitTempArgument()};");
+ }
+ else
+ {
+ codeWriter.WriteLine($"{unwrappedTypeString} {endpointParameter.EmitHandlerArgument()};");
+
+ codeWriter.WriteLine($"if ((object?){endpointParameter.EmitTempArgument()} == null)");
+ codeWriter.StartBlock();
+ codeWriter.WriteLine("wasParamCheckFailure = true;");
+ codeWriter.WriteLine($"{endpointParameter.EmitHandlerArgument()} = default!;");
+ codeWriter.EndBlock();
+ codeWriter.WriteLine("else");
+ codeWriter.StartBlock();
+ codeWriter.WriteLine($"{endpointParameter.EmitHandlerArgument()} = ({unwrappedTypeString}){endpointParameter.EmitTempArgument()};");
+ codeWriter.EndBlock();
+ }
+ }
+
internal static void EmitServiceParameterPreparation(this EndpointParameter endpointParameter, CodeWriter codeWriter)
{
codeWriter.WriteLine(endpointParameter.EmitParameterDiagnosticComment());
diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs
index 83cf8bf65bdb..73d25920e9cf 100644
--- a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs
+++ b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
+using Microsoft.AspNetCore.Analyzers.Infrastructure;
using Microsoft.AspNetCore.App.Analyzers.Infrastructure;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -47,21 +47,36 @@ public Endpoint(IInvocationOperation operation, WellKnownTypes wellKnownTypes)
{
var parameter = new EndpointParameter(method.Parameters[i], wellKnownTypes);
- if (parameter.Source == EndpointParameterSource.Unknown)
+ switch (parameter.Source)
{
- Diagnostics.Add(DiagnosticDescriptors.GetUnableToResolveParameterDescriptor(parameter.Name));
- return;
+ case EndpointParameterSource.BindAsync:
+ IsAwaitable = true;
+ switch (parameter.BindMethod)
+ {
+ case BindabilityMethod.IBindableFromHttpContext:
+ case BindabilityMethod.BindAsyncWithParameter:
+ NeedsParameterArray = true;
+ break;
+ }
+ break;
+ case EndpointParameterSource.JsonBody:
+ case EndpointParameterSource.JsonBodyOrService:
+ IsAwaitable = true;
+ break;
+ case EndpointParameterSource.Unknown:
+ Diagnostics.Add(DiagnosticDescriptors.GetUnableToResolveParameterDescriptor(parameter.Name));
+ break;
}
parameters[i] = parameter;
}
Parameters = parameters;
- IsAwaitable |= parameters.Any(parameter => parameter.Source == EndpointParameterSource.JsonBody);
}
public string HttpMethod { get; }
- public bool IsAwaitable { get; set; }
+ public bool IsAwaitable { get; }
+ public bool NeedsParameterArray { get; }
public string? RoutePattern { get; }
public EndpointResponse? Response { get; }
public EndpointParameter[] Parameters { get; } = Array.Empty();
diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs
index 0f6a01c6cde1..d1a12e428d1d 100644
--- a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs
+++ b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs
@@ -3,13 +3,11 @@
using System;
using System.Diagnostics.CodeAnalysis;
-using Microsoft.AspNetCore.App.Analyzers.Infrastructure;
+using Microsoft.AspNetCore.Analyzers.Infrastructure;
using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure;
+using Microsoft.AspNetCore.App.Analyzers.Infrastructure;
using Microsoft.CodeAnalysis;
using WellKnownType = Microsoft.AspNetCore.App.Analyzers.Infrastructure.WellKnownTypeData.WellKnownType;
-using Microsoft.AspNetCore.Analyzers.Infrastructure;
-using System.Linq;
-using System.Globalization;
namespace Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel;
@@ -19,35 +17,28 @@ public EndpointParameter(IParameterSymbol parameter, WellKnownTypes wellKnownTyp
{
Type = parameter.Type;
Name = parameter.Name;
+ Ordinal = parameter.Ordinal;
Source = EndpointParameterSource.Unknown;
+ IsOptional = parameter.IsOptional();
- var fromQueryMetadataInterfaceType = wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromQueryMetadata);
- var fromServiceMetadataInterfaceType = wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromServiceMetadata);
- var fromRouteMetadataInterfaceType = wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromRouteMetadata);
- var fromHeaderMetadataInterfaceType = wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromHeaderMetadata);
-
- if (parameter.HasAttributeImplementingInterface(fromRouteMetadataInterfaceType, out var fromRouteAttribute))
+ if (parameter.HasAttributeImplementingInterface(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromRouteMetadata), out var fromRouteAttribute))
{
Source = EndpointParameterSource.Route;
Name = GetParameterName(fromRouteAttribute, parameter.Name);
- IsOptional = parameter.IsOptional();
IsParsable = TryGetParsability(parameter, wellKnownTypes, out var parsingBlockEmitter);
ParsingBlockEmitter = parsingBlockEmitter;
}
- else if (parameter.HasAttributeImplementingInterface(fromQueryMetadataInterfaceType, out var fromQueryAttribute))
+ else if (parameter.HasAttributeImplementingInterface(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromQueryMetadata), out var fromQueryAttribute))
{
Source = EndpointParameterSource.Query;
Name = GetParameterName(fromQueryAttribute, parameter.Name);
- IsOptional = parameter.IsOptional();
- AssigningCode = $"httpContext.Request.Query[\"{parameter.Name}\"]";
IsParsable = TryGetParsability(parameter, wellKnownTypes, out var parsingBlockEmitter);
ParsingBlockEmitter = parsingBlockEmitter;
}
- else if (parameter.HasAttributeImplementingInterface(fromHeaderMetadataInterfaceType, out var fromHeaderAttribute))
+ else if (parameter.HasAttributeImplementingInterface(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromHeaderMetadata), out var fromHeaderAttribute))
{
Source = EndpointParameterSource.Header;
Name = GetParameterName(fromHeaderAttribute, parameter.Name);
- IsOptional = parameter.IsOptional();
IsParsable = TryGetParsability(parameter, wellKnownTypes, out var parsingBlockEmitter);
ParsingBlockEmitter = parsingBlockEmitter;
}
@@ -56,7 +47,7 @@ public EndpointParameter(IParameterSymbol parameter, WellKnownTypes wellKnownTyp
Source = EndpointParameterSource.JsonBody;
IsOptional = isOptional;
}
- else if (parameter.HasAttributeImplementingInterface(fromServiceMetadataInterfaceType))
+ else if (parameter.HasAttributeImplementingInterface(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromServiceMetadata)))
{
Source = EndpointParameterSource.Service;
IsOptional = parameter.Type is INamedTypeSymbol { NullableAnnotation: NullableAnnotation.Annotated } || parameter.HasExplicitDefaultValue;
@@ -66,10 +57,20 @@ public EndpointParameter(IParameterSymbol parameter, WellKnownTypes wellKnownTyp
Source = EndpointParameterSource.SpecialType;
AssigningCode = specialTypeAssigningCode;
}
+ else if (HasBindAsync(parameter, wellKnownTypes, out var bindMethod))
+ {
+ Source = EndpointParameterSource.BindAsync;
+ BindMethod = bindMethod;
+ }
else if (parameter.Type.SpecialType == SpecialType.System_String)
{
Source = EndpointParameterSource.RouteOrQuery;
- IsOptional = parameter.IsOptional();
+ }
+ else if (TryGetParsability(parameter, wellKnownTypes, out var parsingBlockEmitter))
+ {
+ Source = EndpointParameterSource.RouteOrQuery;
+ IsParsable = true;
+ ParsingBlockEmitter = parsingBlockEmitter;
}
else
{
@@ -78,23 +79,46 @@ public EndpointParameter(IParameterSymbol parameter, WellKnownTypes wellKnownTyp
}
}
- private bool TryGetParsability(IParameterSymbol parameter, WellKnownTypes wellKnownTypes, [NotNullWhen(true)]out Action? parsingBlockEmitter)
+ public ITypeSymbol Type { get; }
+ public string Name { get; }
+ public int Ordinal { get; }
+ public bool IsOptional { get; }
+
+ public EndpointParameterSource Source { get; }
+
+ // Only used for SpecialType parameters that need
+ // to be resolved by a specific WellKnownType
+ public string? AssigningCode { get; }
+
+ [MemberNotNullWhen(true, nameof(ParsingBlockEmitter))]
+ public bool IsParsable { get; }
+ public Action? ParsingBlockEmitter { get; }
+
+ public BindabilityMethod? BindMethod { get; }
+
+ private static bool HasBindAsync(IParameterSymbol parameter, WellKnownTypes wellKnownTypes, [NotNullWhen(true)] out BindabilityMethod? bindMethod)
+ {
+ var parameterType = parameter.Type.UnwrapTypeSymbol();
+ return ParsabilityHelper.GetBindability(parameterType, wellKnownTypes, out bindMethod) == Bindability.Bindable;
+ }
+
+ private bool TryGetParsability(IParameterSymbol parameter, WellKnownTypes wellKnownTypes, [NotNullWhen(true)] out Action? parsingBlockEmitter)
{
var parameterType = parameter.Type.UnwrapTypeSymbol();
// ParsabilityHelper returns a single enumeration with a Parsable/NonParsable enumeration result. We use this already
// in the analyzers to determine whether we need to warn on whether a type needs to implement TryParse/IParsable. To
- // support usage in the code generator an optiona out parameter has been added to hint at what variant of the various
+ // support usage in the code generator an optional out parameter has been added to hint at what variant of the various
// TryParse methods should be used (this implies that the preferences are baked into ParsabilityHelper). If we aren't
// parsable at all we bail.
- if (ParsabilityHelper.GetParsability(parameterType, wellKnownTypes, out var parsabilityMethod) == Parsability.NotParsable)
+ if (ParsabilityHelper.GetParsability(parameterType, wellKnownTypes, out var parsabilityMethod) != Parsability.Parsable)
{
parsingBlockEmitter = null;
return false;
}
// If we are parsable we need to emit code based on the enumeration ParsabilityMethod which has a bunch of members
- // which spell out the preferred TryParse uage. This swtich statement makes slight variations to them based on
+ // which spell out the preferred TryParse usage. This switch statement makes slight variations to them based on
// which method was encountered.
Func? preferredTryParseInvocation = parsabilityMethod switch
{
@@ -104,7 +128,7 @@ private bool TryGetParsability(IParameterSymbol parameter, WellKnownTypes wellKn
ParsabilityMethod.Enum => (string inputArgument, string outputArgument) => $$"""Enum.TryParse<{{parameterType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}}>({{inputArgument}}!, out var {{outputArgument}})""",
ParsabilityMethod.Uri => (string inputArgument, string outputArgument) => $$"""Uri.TryCreate({{inputArgument}}!, UriKind.RelativeOrAbsolute, out var {{outputArgument}})""",
ParsabilityMethod.String => null, // string parameters don't require parsing
- _ => null
+ _ => throw new Exception("Unreachable!"),
};
// Special case handling for specific types
@@ -166,18 +190,6 @@ private bool TryGetParsability(IParameterSymbol parameter, WellKnownTypes wellKn
return true;
}
- public ITypeSymbol Type { get; }
- public EndpointParameterSource Source { get; }
-
- // Only used for SpecialType parameters that need
- // to be resolved by a specific WellKnownType
- internal string? AssigningCode { get; set; }
- public string Name { get; }
- public bool IsOptional { get; }
- [MemberNotNull("ParsingBlockEmitter")]
- public bool IsParsable { get; }
- public Action ParsingBlockEmitter { get; }
-
// TODO: Handle special form types like IFormFileCollection that need special body-reading logic.
private static bool TryGetSpecialTypeAssigningCode(ITypeSymbol type, WellKnownTypes wellKnownTypes, [NotNullWhen(true)] out string? callingCode)
{
@@ -245,6 +257,8 @@ public override bool Equals(object obj) =>
obj is EndpointParameter other &&
other.Source == Source &&
other.Name == Name &&
+ other.Ordinal == Ordinal &&
+ other.IsOptional == IsOptional &&
SymbolEqualityComparer.Default.Equals(other.Type, Type);
public bool SignatureEquals(object obj) =>
diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
index f0a605a077af..878c5a6361c5 100644
--- a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
+++ b/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
@@ -2,9 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.CodeDom.Compiler;
-using System.Globalization;
-using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Http.Generators.StaticRouteHandlerModel.Emitters;
@@ -110,7 +107,14 @@ public static void EmitRequestHandler(this Endpoint endpoint, CodeWriter codeWri
codeWriter.Write("await ");
}
codeWriter.WriteLine($"handler({endpoint.EmitArgumentList()});");
- codeWriter.WriteLine(endpoint.Response.IsVoid ? "return Task.CompletedTask;" : endpoint.EmitResponseWritingCall());
+ if (!endpoint.Response.IsVoid)
+ {
+ codeWriter.WriteLine(endpoint.EmitResponseWritingCall());
+ }
+ else if (!endpoint.IsAwaitable)
+ {
+ codeWriter.WriteLine("return Task.CompletedTask;");
+ }
codeWriter.EndBlock(); // End handler method block
}
diff --git a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj
index b6a0988e5a9f..01cfa420bd6d 100644
--- a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj
+++ b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj
@@ -29,7 +29,7 @@
- PreserveNewest
+ Always
diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
index 5695c4e92df6..782c42fe5b83 100644
--- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
+++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
@@ -628,12 +628,6 @@ public static bool TryParse(string? value, out MyTryParseRecord? result)
}
}
- private class MyBindAsyncTypeThatThrows
- {
- public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter) =>
- throw new InvalidOperationException("BindAsync failed");
- }
-
private record MyBindAsyncRecord(Uri Uri)
{
public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter)
@@ -1123,79 +1117,6 @@ public async Task RequestDelegatePopulatesUnattributedTryParsableParametersFromR
Assert.Equal(42, httpContext.Items["tryParsable"]);
}
- [Fact]
- public async Task RequestDelegatePrefersBindAsyncOverTryParse()
- {
- var httpContext = CreateHttpContext();
-
- httpContext.Request.Headers.Referer = "https://example.org";
-
- var resultFactory = RequestDelegateFactory.Create((HttpContext httpContext, MyBindAsyncRecord myBindAsyncRecord) =>
- {
- httpContext.Items["myBindAsyncRecord"] = myBindAsyncRecord;
- });
-
- var requestDelegate = resultFactory.RequestDelegate;
-
- await requestDelegate(httpContext);
-
- Assert.Equal(new MyBindAsyncRecord(new Uri("https://example.org")), httpContext.Items["myBindAsyncRecord"]);
- }
-
- [Fact]
- public async Task RequestDelegatePrefersBindAsyncOverTryParseForNonNullableStruct()
- {
- var httpContext = CreateHttpContext();
-
- httpContext.Request.Headers.Referer = "https://example.org";
-
- var resultFactory = RequestDelegateFactory.Create((HttpContext httpContext, MyBindAsyncStruct myBindAsyncStruct) =>
- {
- httpContext.Items["myBindAsyncStruct"] = myBindAsyncStruct;
- });
-
- var requestDelegate = resultFactory.RequestDelegate;
- await requestDelegate(httpContext);
-
- Assert.Equal(new MyBindAsyncStruct(new Uri("https://example.org")), httpContext.Items["myBindAsyncStruct"]);
- }
-
- [Fact]
- public async Task RequestDelegateUsesBindAsyncOverTryParseGivenNullableStruct()
- {
- var httpContext = CreateHttpContext();
-
- httpContext.Request.Headers.Referer = "https://example.org";
-
- var resultFactory = RequestDelegateFactory.Create((HttpContext httpContext, MyBindAsyncStruct? myBindAsyncStruct) =>
- {
- httpContext.Items["myBindAsyncStruct"] = myBindAsyncStruct;
- });
-
- var requestDelegate = resultFactory.RequestDelegate;
- await requestDelegate(httpContext);
-
- Assert.Equal(new MyBindAsyncStruct(new Uri("https://example.org")), httpContext.Items["myBindAsyncStruct"]);
- }
-
- [Fact]
- public async Task RequestDelegateUsesParameterInfoBindAsyncOverOtherBindAsync()
- {
- var httpContext = CreateHttpContext();
-
- httpContext.Request.Headers.Referer = "https://example.org";
-
- var resultFactory = RequestDelegateFactory.Create((HttpContext httpContext, MyBothBindAsyncStruct? myBothBindAsyncStruct) =>
- {
- httpContext.Items["myBothBindAsyncStruct"] = myBothBindAsyncStruct;
- });
-
- var requestDelegate = resultFactory.RequestDelegate;
- await requestDelegate(httpContext);
-
- Assert.Equal(new MyBothBindAsyncStruct(new Uri("https://example.org")), httpContext.Items["myBothBindAsyncStruct"]);
- }
-
[Fact]
public async Task RequestDelegateUsesTryParseOverBindAsyncGivenExplicitAttribute()
{
@@ -1554,19 +1475,6 @@ public async Task RequestDelegateThrowsForSingleArgBindAsyncFailuresIfThrowOnBad
Assert.Equal(400, badHttpRequestException.StatusCode);
}
- [Fact]
- public async Task BindAsyncExceptionsAreUncaught()
- {
- var httpContext = CreateHttpContext();
-
- var factoryResult = RequestDelegateFactory.Create((MyBindAsyncTypeThatThrows arg1) => { });
-
- var requestDelegate = factoryResult.RequestDelegate;
-
- var ex = await Assert.ThrowsAsync(() => requestDelegate(httpContext));
- Assert.Equal("BindAsync failed", ex.Message);
- }
-
[Fact]
public async Task BindAsyncWithBodyArgument()
{
diff --git a/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt b/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt
new file mode 100644
index 000000000000..26d1d5942c52
--- /dev/null
+++ b/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt
@@ -0,0 +1,1726 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+#nullable enable
+
+namespace Microsoft.AspNetCore.Builder
+{
+ %GENERATEDCODEATTRIBUTE%
+ internal class SourceKey
+ {
+ public string Path { get; init; }
+ public int Line { get; init; }
+
+ public SourceKey(string path, int line)
+ {
+ Path = path;
+ Line = line;
+ }
+ }
+
+ // This class needs to be internal so that the compiled application
+ // has access to the strongly-typed endpoint definitions that are
+ // generated by the compiler so that they will be favored by
+ // overload resolution and opt the runtime in to the code generated
+ // implementation produced here.
+ %GENERATEDCODEATTRIBUTE%
+ internal static class GenerateRouteBuilderEndpoints
+ {
+ private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
+ private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
+ private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
+ private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
+ private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };
+
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+ internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
+ this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax("Route")] string pattern,
+ global::System.Func handler,
+ [global::System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
+ [global::System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0)
+ {
+ return global::Microsoft.AspNetCore.Http.Generated.GeneratedRouteBuilderExtensionsCore.MapCore(
+ endpoints,
+ pattern,
+ handler,
+ GetVerb,
+ filePath,
+ lineNumber);
+ }
+
+ }
+}
+
+namespace Microsoft.AspNetCore.Http.Generated
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Globalization;
+ using System.Linq;
+ using System.Reflection;
+ using System.Text.Json;
+ using System.Text.Json.Serialization.Metadata;
+ using System.Threading.Tasks;
+ using System.IO;
+ using Microsoft.AspNetCore.Routing;
+ using Microsoft.AspNetCore.Routing.Patterns;
+ using Microsoft.AspNetCore.Builder;
+ using Microsoft.AspNetCore.Http;
+ using Microsoft.AspNetCore.Http.Json;
+ using Microsoft.AspNetCore.Http.Metadata;
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.FileProviders;
+ using Microsoft.Extensions.Primitives;
+ using Microsoft.Extensions.Options;
+
+ using MetadataPopulator = System.Func;
+ using RequestDelegateFactoryFunc = System.Func;
+
+ file static class GeneratedRouteBuilderExtensionsCore
+ {
+
+ private static readonly Dictionary<(string, int), (MetadataPopulator, RequestDelegateFactoryFunc)> map = new()
+ {
+ [(@"TestMapActions.cs", 24)] = (
+ (methodInfo, options) =>
+ {
+ Debug.Assert(options?.EndpointBuilder != null, "EndpointBuilder not found.");
+ options.EndpointBuilder.Metadata.Add(new SourceKey(@"TestMapActions.cs", 24));
+ return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
+ },
+ (del, options, inferredMetadataResult) =>
+ {
+ var handler = (Func)del;
+ EndpointFilterDelegate? filteredInvocation = null;
+ var parameters = del.Method.GetParameters();
+
+ if (options?.EndpointBuilder?.FilterFactories.Count > 0)
+ {
+ filteredInvocation = GeneratedRouteBuilderExtensionsCore.BuildFilterDelegate(ic =>
+ {
+ if (ic.HttpContext.Response.StatusCode == 400)
+ {
+ return ValueTask.FromResult