From 64a94f01ecb7fadeaffd242e159ae593e117c23c Mon Sep 17 00:00:00 2001 From: Stephen Halter <halter73@gmail.com> Date: Mon, 29 Mar 2021 17:21:36 -0700 Subject: [PATCH] Make RequestDelegateFactory public (was MapActionExpressionTreeBuilder) (#31171) * Make RequestDelegateBuilder public - Formerly known as MapActionExpressionTreeBuilder * Add new BuildRequestDelegate overloads * Address PR feedback * RequestDelegateBuilder -> RequestDelegateFactory * Build -> Create * Address final review feedback. --- ...icrosoft.AspNetCore.Http.Extensions.csproj | 1 + .../src/PublicAPI.Unshipped.txt | 4 + .../src/RequestDelegateFactory.cs} | 146 ++++++++++++----- .../test/RequestDelegateFactoryTests.cs} | 153 ++++++++++++++---- ...MapActionEndpointRouteBuilderExtensions.cs | 4 +- .../src/Microsoft.AspNetCore.Routing.csproj | 1 - 6 files changed, 240 insertions(+), 69 deletions(-) rename src/Http/{Routing/src/Internal/MapActionExpressionTreeBuilder.cs => Http.Extensions/src/RequestDelegateFactory.cs} (79%) rename src/Http/{Routing/test/UnitTests/Internal/MapActionExpressionTreeBuilderTest.cs => Http.Extensions/test/RequestDelegateFactoryTests.cs} (85%) diff --git a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj index 123ae96be7a..94a3e73732a 100644 --- a/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj +++ b/src/Http/Http.Extensions/src/Microsoft.AspNetCore.Http.Extensions.csproj @@ -11,6 +11,7 @@ </PropertyGroup> <ItemGroup> + <Compile Include="$(SharedSourceRoot)ObjectMethodExecutor\**\*.cs" /> <Compile Include="..\..\Shared\StreamCopyOperationInternal.cs" Link="StreamCopyOperationInternal.cs" /> </ItemGroup> diff --git a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt index c82589d1209..33854973715 100644 --- a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt @@ -152,6 +152,7 @@ Microsoft.AspNetCore.Http.Headers.ResponseHeaders.Set(string! name, object? valu Microsoft.AspNetCore.Http.Headers.ResponseHeaders.SetCookie.get -> System.Collections.Generic.IList<Microsoft.Net.Http.Headers.SetCookieHeaderValue!>! Microsoft.AspNetCore.Http.Headers.ResponseHeaders.SetCookie.set -> void Microsoft.AspNetCore.Http.Headers.ResponseHeaders.SetList<T>(string! name, System.Collections.Generic.IList<T>? values) -> void +Microsoft.AspNetCore.Http.RequestDelegateFactory override Microsoft.AspNetCore.Http.Extensions.QueryBuilder.Equals(object? obj) -> bool override Microsoft.AspNetCore.Http.Extensions.QueryBuilder.ToString() -> string! static Microsoft.AspNetCore.Http.Extensions.HttpRequestMultipartExtensions.GetMultipartBoundary(this Microsoft.AspNetCore.Http.HttpRequest! request) -> string! @@ -168,6 +169,9 @@ static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.AppendList<T>(th static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpRequest! request) -> Microsoft.AspNetCore.Http.Headers.RequestHeaders! static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpResponse! response) -> Microsoft.AspNetCore.Http.Headers.ResponseHeaders! static Microsoft.AspNetCore.Http.HttpContextServerVariableExtensions.GetServerVariable(this Microsoft.AspNetCore.Http.HttpContext! context, string! variableName) -> string? +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Delegate! action) -> Microsoft.AspNetCore.Http.RequestDelegate! +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo) -> Microsoft.AspNetCore.Http.RequestDelegate! +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.Func<Microsoft.AspNetCore.Http.HttpContext!, object!>! targetFactory) -> Microsoft.AspNetCore.Http.RequestDelegate! static Microsoft.AspNetCore.Http.ResponseExtensions.Clear(this Microsoft.AspNetCore.Http.HttpResponse! response) -> void static Microsoft.AspNetCore.Http.ResponseExtensions.Redirect(this Microsoft.AspNetCore.Http.HttpResponse! response, string! location, bool permanent, bool preserveMethod) -> void static Microsoft.AspNetCore.Http.SendFileResponseExtensions.SendFileAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, Microsoft.Extensions.FileProviders.IFileInfo! file, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! diff --git a/src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs similarity index 79% rename from src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs rename to src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 1e83d92c349..948c77fd094 100644 --- a/src/Http/Routing/src/Internal/MapActionExpressionTreeBuilder.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -11,24 +11,26 @@ using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Http { - internal static class MapActionExpressionTreeBuilder + /// <summary> + /// Creates <see cref="RequestDelegate"/> implementations from <see cref="Delegate"/> request handlers. + /// </summary> + public static class RequestDelegateFactory { private static readonly MethodInfo ChangeTypeMethodInfo = GetMethodInfo<Func<object, Type, object>>((value, type) => Convert.ChangeType(value, type, CultureInfo.InvariantCulture)); - private static readonly MethodInfo ExecuteTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteTask), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteTaskOfStringMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteTaskOfString), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteValueTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTaskOfT), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteValueTaskMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTask), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteValueTaskOfStringMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTaskOfString), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteTaskResultOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo ExecuteValueResultTaskOfTMethodInfo = typeof(MapActionExpressionTreeBuilder).GetMethod(nameof(ExecuteValueTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteTaskOfTMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteTask), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteTaskOfStringMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteTaskOfString), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteValueTaskOfTMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteValueTaskOfT), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteValueTaskMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteValueTask), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteValueTaskOfStringMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteValueTaskOfString), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteTaskResultOfTMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!; + private static readonly MethodInfo ExecuteValueResultTaskOfTMethodInfo = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteValueTaskResult), BindingFlags.NonPublic | BindingFlags.Static)!; private static readonly MethodInfo GetRequiredServiceMethodInfo = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), BindingFlags.Public | BindingFlags.Static, new Type[] { typeof(IServiceProvider) })!; private static readonly MethodInfo ResultWriteResponseAsync = typeof(IResult).GetMethod(nameof(IResult.ExecuteAsync), BindingFlags.Public | BindingFlags.Instance)!; private static readonly MethodInfo StringResultWriteResponseAsync = GetMethodInfo<Func<HttpResponse, string, Task>>((response, text) => HttpResponseWritingExtensions.WriteAsync(response, text, default)); @@ -44,7 +46,85 @@ namespace Microsoft.AspNetCore.Routing.Internal private static readonly MemberExpression HttpResponseExpr = Expression.Property(HttpContextParameter, nameof(HttpContext.Response)); private static readonly MemberExpression RequestAbortedExpr = Expression.Property(HttpContextParameter, nameof(HttpContext.RequestAborted)); - public static RequestDelegate BuildRequestDelegate(Delegate action) + /// <summary> + /// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="action"/>. + /// </summary> + /// <param name="action">A request handler with any number of custom parameters that often produces a response with its return value.</param> + /// <returns>The <see cref="RequestDelegate"/>.</returns> + public static RequestDelegate Create(Delegate action) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + var targetExpression = action.Target switch + { + object => Expression.Convert(TargetArg, action.Target.GetType()), + null => null, + }; + + var untargetedRequestDelegate = CreateRequestDelegate(action.Method, targetExpression); + + return httpContext => + { + return untargetedRequestDelegate(action.Target, httpContext); + }; + } + + /// <summary> + /// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>. + /// </summary> + /// <param name="methodInfo">A static request handler with any number of custom parameters that often produces a response with its return value.</param> + /// <returns>The <see cref="RequestDelegate"/>.</returns> + public static RequestDelegate Create(MethodInfo methodInfo) + { + if (methodInfo is null) + { + throw new ArgumentNullException(nameof(methodInfo)); + } + + var untargetedRequestDelegate = CreateRequestDelegate(methodInfo, targetExpression: null); + + return httpContext => + { + return untargetedRequestDelegate(null, httpContext); + }; + } + + /// <summary> + /// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>. + /// </summary> + /// <param name="methodInfo">A request handler with any number of custom parameters that often produces a response with its return value.</param> + /// <param name="targetFactory">Creates the <see langword="this"/> for the non-static method.</param> + /// <returns>The <see cref="RequestDelegate"/>.</returns> + public static RequestDelegate Create(MethodInfo methodInfo, Func<HttpContext, object> targetFactory) + { + if (methodInfo is null) + { + throw new ArgumentNullException(nameof(methodInfo)); + } + + if (targetFactory is null) + { + throw new ArgumentNullException(nameof(targetFactory)); + } + + if (methodInfo.DeclaringType is null) + { + throw new ArgumentException($"A {nameof(targetFactory)} was provided, but {nameof(methodInfo)} does not have a Declaring type."); + } + + var targetExpression = Expression.Convert(TargetArg, methodInfo.DeclaringType); + var untargetedRequestDelegate = CreateRequestDelegate(methodInfo, targetExpression); + + return httpContext => + { + return untargetedRequestDelegate(targetFactory(httpContext), httpContext); + }; + } + + private static Func<object?, HttpContext, Task> CreateRequestDelegate(MethodInfo methodInfo, Expression? targetExpression) { // Non void return type @@ -62,8 +142,6 @@ namespace Microsoft.AspNetCore.Routing.Internal // return default; // } - var method = action.Method; - var consumeBodyDirectly = false; var consumeBodyAsForm = false; Type? bodyType = null; @@ -72,7 +150,7 @@ namespace Microsoft.AspNetCore.Routing.Internal // This argument represents the deserialized body returned from IHttpRequestReader // when the method has a FromBody attribute declared - var methodParameters = method.GetParameters(); + var methodParameters = methodInfo.GetParameters(); var args = new List<Expression>(methodParameters.Length); foreach (var parameter in methodParameters) @@ -156,18 +234,17 @@ namespace Microsoft.AspNetCore.Routing.Internal MethodCallExpression methodCall; - if (action.Target is null) + if (targetExpression is null) { - methodCall = Expression.Call(method, args); + methodCall = Expression.Call(methodInfo, args); } else { - var castedTarget = Expression.Convert(TargetArg, action.Target.GetType()); - methodCall = Expression.Call(castedTarget, method, args); + methodCall = Expression.Call(targetExpression, methodInfo, args); } // Exact request delegate match - if (method.ReturnType == typeof(void)) + if (methodInfo.ReturnType == typeof(void)) { var bodyExpressions = new List<Expression> { @@ -177,22 +254,22 @@ namespace Microsoft.AspNetCore.Routing.Internal body = Expression.Block(bodyExpressions); } - else if (AwaitableInfo.IsTypeAwaitable(method.ReturnType, out var info)) + else if (AwaitableInfo.IsTypeAwaitable(methodInfo.ReturnType, out var info)) { - if (method.ReturnType == typeof(Task)) + if (methodInfo.ReturnType == typeof(Task)) { body = methodCall; } - else if (method.ReturnType == typeof(ValueTask)) + else if (methodInfo.ReturnType == typeof(ValueTask)) { body = Expression.Call( ExecuteValueTaskMethodInfo, methodCall); } - else if (method.ReturnType.IsGenericType && - method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + else if (methodInfo.ReturnType.IsGenericType && + methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { - var typeArg = method.ReturnType.GetGenericArguments()[0]; + var typeArg = methodInfo.ReturnType.GetGenericArguments()[0]; if (typeof(IResult).IsAssignableFrom(typeArg)) { @@ -220,10 +297,10 @@ namespace Microsoft.AspNetCore.Routing.Internal } } } - else if (method.ReturnType.IsGenericType && - method.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) + else if (methodInfo.ReturnType.IsGenericType && + methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) { - var typeArg = method.ReturnType.GetGenericArguments()[0]; + var typeArg = methodInfo.ReturnType.GetGenericArguments()[0]; if (typeof(IResult).IsAssignableFrom(typeArg)) { @@ -254,18 +331,18 @@ namespace Microsoft.AspNetCore.Routing.Internal else { // TODO: Handle custom awaitables - throw new NotSupportedException($"Unsupported return type: {method.ReturnType}"); + throw new NotSupportedException($"Unsupported return type: {methodInfo.ReturnType}"); } } - else if (typeof(IResult).IsAssignableFrom(method.ReturnType)) + else if (typeof(IResult).IsAssignableFrom(methodInfo.ReturnType)) { body = Expression.Call(methodCall, ResultWriteResponseAsync, HttpContextParameter); } - else if (method.ReturnType == typeof(string)) + else if (methodInfo.ReturnType == typeof(string)) { body = Expression.Call(StringResultWriteResponseAsync, HttpResponseExpr, methodCall, Expression.Constant(CancellationToken.None)); } - else if (method.ReturnType.IsValueType) + else if (methodInfo.ReturnType.IsValueType) { var box = Expression.TypeAs(methodCall, typeof(object)); body = Expression.Call(JsonResultWriteResponseAsync, HttpResponseExpr, box, Expression.Constant(CancellationToken.None)); @@ -357,10 +434,7 @@ namespace Microsoft.AspNetCore.Routing.Internal requestDelegate = invoker; } - return httpContext => - { - return requestDelegate(action.Target, httpContext); - }; + return requestDelegate; } private static ILogger GetLogger(HttpContext httpContext) diff --git a/src/Http/Routing/test/UnitTests/Internal/MapActionExpressionTreeBuilderTest.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs similarity index 85% rename from src/Http/Routing/test/UnitTests/Internal/MapActionExpressionTreeBuilderTest.cs rename to src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index 39372600077..36d4004cfbe 100644 --- a/src/Http/Routing/test/UnitTests/Internal/MapActionExpressionTreeBuilderTest.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Reflection; using System.Text; using System.Text.Json; using System.Threading; @@ -22,7 +23,7 @@ using Xunit; namespace Microsoft.AspNetCore.Routing.Internal { - public class MapActionExpressionTreeBuilderTest + public class RequestDelegateFactoryTests { public static IEnumerable<object[]> NoResult { @@ -85,13 +86,105 @@ namespace Microsoft.AspNetCore.Routing.Internal { var httpContext = new DefaultHttpContext(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); Assert.True(httpContext.Items["invoked"] as bool?); } + private static void StaticTestActionBasicReflection(HttpContext httpContext) + { + httpContext.Items.Add("invoked", true); + } + + [Fact] + public async Task StaticMethodInfoOverloadWorksWithBasicReflection() + { + var methodInfo = typeof(RequestDelegateFactoryTests).GetMethod( + nameof(StaticTestActionBasicReflection), + BindingFlags.NonPublic | BindingFlags.Static, + new[] { typeof(HttpContext) }); + + var requestDelegate = RequestDelegateFactory.Create(methodInfo!); + + var httpContext = new DefaultHttpContext(); + + await requestDelegate(httpContext); + + Assert.True(httpContext.Items["invoked"] as bool?); + } + + private class TestNonStaticActionClass + { + private readonly object _invokedValue; + + public TestNonStaticActionClass(object invokedValue) + { + _invokedValue = invokedValue; + } + + private void NonStaticTestAction(HttpContext httpContext) + { + httpContext.Items.Add("invoked", _invokedValue); + } + } + + [Fact] + public async Task NonStaticMethodInfoOverloadWorksWithBasicReflection() + { + var methodInfo = typeof(TestNonStaticActionClass).GetMethod( + "NonStaticTestAction", + BindingFlags.NonPublic | BindingFlags.Instance, + new[] { typeof(HttpContext) }); + + var invoked = false; + + object GetTarget() + { + if (!invoked) + { + invoked = true; + return new TestNonStaticActionClass(1); + } + + return new TestNonStaticActionClass(2); + } + + var requestDelegate = RequestDelegateFactory.Create(methodInfo!, _ => GetTarget()); + + var httpContext = new DefaultHttpContext(); + + await requestDelegate(httpContext); + + Assert.Equal(1, httpContext.Items["invoked"]); + + httpContext = new DefaultHttpContext(); + + await requestDelegate(httpContext); + + Assert.Equal(2, httpContext.Items["invoked"]); + } + + [Fact] + public void BuildRequestDelegateThrowsArgumentNullExceptions() + { + var methodInfo = typeof(RequestDelegateFactoryTests).GetMethod( + nameof(StaticTestActionBasicReflection), + BindingFlags.NonPublic | BindingFlags.Static, + new[] { typeof(HttpContext) }); + + var exNullAction = Assert.Throws<ArgumentNullException>(() => RequestDelegateFactory.Create(action: null!)); + var exNullMethodInfo1 = Assert.Throws<ArgumentNullException>(() => RequestDelegateFactory.Create(methodInfo: null!)); + var exNullMethodInfo2 = Assert.Throws<ArgumentNullException>(() => RequestDelegateFactory.Create(methodInfo: null!, _ => 0)); + var exNullTargetFactory = Assert.Throws<ArgumentNullException>(() => RequestDelegateFactory.Create(methodInfo!, targetFactory: null!)); + + Assert.Equal("action", exNullAction.ParamName); + Assert.Equal("methodInfo", exNullMethodInfo1.ParamName); + Assert.Equal("methodInfo", exNullMethodInfo2.ParamName); + Assert.Equal("targetFactory", exNullTargetFactory.ParamName); + } + public static IEnumerable<object[]> FromRouteResult { get @@ -136,7 +229,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -179,7 +272,7 @@ namespace Microsoft.AspNetCore.Routing.Internal { var httpContext = new DefaultHttpContext(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -197,7 +290,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -220,7 +313,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[specifiedName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -243,7 +336,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[unmatchedName] = unmatchedRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -271,7 +364,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.Query = query; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -294,7 +387,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.Headers[customHeaderName] = originalHeaderParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -322,7 +415,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var requestBodyBytes = JsonSerializer.SerializeToUtf8Bytes(originalTodo); httpContext.Request.Body = new MemoryStream(requestBodyBytes); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<Todo>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<Todo>)TestAction); await requestDelegate(httpContext); @@ -341,7 +434,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<Todo>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<Todo>)TestAction); await Assert.ThrowsAsync<JsonException>(() => requestDelegate(httpContext)); } @@ -360,7 +453,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<Todo>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<Todo>)TestAction); await requestDelegate(httpContext); @@ -384,7 +477,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<BodyStruct>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<BodyStruct>)TestAction); await requestDelegate(httpContext); @@ -414,7 +507,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Features.Set<IHttpRequestLifetimeFeature>(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<Todo>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<Todo>)TestAction); await requestDelegate(httpContext); @@ -450,7 +543,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Features.Set<IHttpRequestLifetimeFeature>(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<Todo>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<Todo>)TestAction); await requestDelegate(httpContext); @@ -485,7 +578,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.Form = form; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -515,7 +608,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Features.Set<IHttpRequestLifetimeFeature>(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -551,7 +644,7 @@ namespace Microsoft.AspNetCore.Routing.Internal httpContext.Features.Set<IHttpRequestLifetimeFeature>(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<int>)TestAction); await requestDelegate(httpContext); @@ -571,8 +664,8 @@ namespace Microsoft.AspNetCore.Routing.Internal void TestAction([FromBody] int value1, [FromForm] int value2) { } void TestActionWithFlippedParams([FromForm] int value1, [FromBody] int value2) { } - Assert.Throws<InvalidOperationException>(() => MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int, int>)TestAction)); - Assert.Throws<InvalidOperationException>(() => MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int, int>)TestActionWithFlippedParams)); + Assert.Throws<InvalidOperationException>(() => RequestDelegateFactory.Create((Action<int, int>)TestAction)); + Assert.Throws<InvalidOperationException>(() => RequestDelegateFactory.Create((Action<int, int>)TestActionWithFlippedParams)); } [Fact] @@ -580,7 +673,7 @@ namespace Microsoft.AspNetCore.Routing.Internal { void TestAction([FromBody] int value1, [FromBody] int value2) { } - Assert.Throws<InvalidOperationException>(() => MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<int, int>)TestAction)); + Assert.Throws<InvalidOperationException>(() => RequestDelegateFactory.Create((Action<int, int>)TestAction)); } [Fact] @@ -600,7 +693,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<MyService>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<MyService>)TestAction); await requestDelegate(httpContext); @@ -619,7 +712,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<HttpContext>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<HttpContext>)TestAction); await requestDelegate(httpContext); @@ -639,7 +732,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var httpContext = new DefaultHttpContext(); httpContext.Request.Headers["Content-Type"] = "application/x-www-form-urlencoded"; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<IFormCollection>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<IFormCollection>)TestAction); await requestDelegate(httpContext); @@ -662,7 +755,7 @@ namespace Microsoft.AspNetCore.Routing.Internal RequestAborted = cts.Token }; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate((Action<CancellationToken>)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action<CancellationToken>)TestAction); await requestDelegate(httpContext); @@ -706,7 +799,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -755,7 +848,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -798,7 +891,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -839,7 +932,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); @@ -880,7 +973,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = MapActionExpressionTreeBuilder.BuildRequestDelegate(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext); diff --git a/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs b/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs index e816c1cdb77..e071bae5ac8 100644 --- a/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs +++ b/src/Http/Routing/src/Builder/MapActionEndpointRouteBuilderExtensions.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Patterns; namespace Microsoft.AspNetCore.Builder @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Builder const int defaultOrder = 0; var builder = new RouteEndpointBuilder( - MapActionExpressionTreeBuilder.BuildRequestDelegate(action), + RequestDelegateFactory.Create(action), pattern, defaultOrder) { diff --git a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj index 67723bd1d17..e96f32ceddf 100644 --- a/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj +++ b/src/Http/Routing/src/Microsoft.AspNetCore.Routing.csproj @@ -24,7 +24,6 @@ Microsoft.AspNetCore.Routing.RouteCollection</Description> <ItemGroup> <Compile Include="$(SharedSourceRoot)PropertyHelper\*.cs" /> - <Compile Include="$(SharedSourceRoot)ObjectMethodExecutor\**\*.cs" /> </ItemGroup> <ItemGroup> -- GitLab