Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrennan Conroy <brecon@microsoft.com>2022-04-15 02:39:47 +0300
committerBrennan Conroy <brecon@microsoft.com>2022-04-15 02:54:59 +0300
commit7ef19233a06f56f073bb1a9b3d174217ac243dd3 (patch)
tree438dc10f5a7205991d5ec9fab5c37819ba028ca5
parent426949d51ed64faa97bf2138417a737996267e08 (diff)
Fix endpoint filters with inline delegatebrecon/filternull
-rw-r--r--src/Http/Http.Extensions/src/RequestDelegateFactory.cs41
-rw-r--r--src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs40
2 files changed, 68 insertions, 13 deletions
diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
index 7b25889d0c..745a8b120e 100644
--- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
+++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
@@ -113,7 +113,7 @@ public static partial class RequestDelegateFactory
throw new ArgumentNullException(nameof(handler));
}
- var targetExpression = handler.Target switch
+ var targetConvertMethod = handler.Target switch
{
object => Expression.Convert(TargetExpr, handler.Target.GetType()),
null => null,
@@ -121,7 +121,7 @@ public static partial class RequestDelegateFactory
var factoryContext = CreateFactoryContext(options);
- var targetableRequestDelegate = CreateTargetableRequestDelegate(handler.Method, targetExpression, factoryContext);
+ var targetableRequestDelegate = CreateTargetableRequestDelegate(handler.Method, targetConvertMethod, factoryContext, handler.Target);
return new RequestDelegateResult(httpContext => targetableRequestDelegate(handler.Target, httpContext), factoryContext.Metadata);
}
@@ -153,7 +153,7 @@ public static partial class RequestDelegateFactory
{
if (methodInfo.IsStatic)
{
- var untargetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, targetExpression: null, factoryContext);
+ var untargetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, targetConvertMethod: null, factoryContext);
return new RequestDelegateResult(httpContext => untargetableRequestDelegate(null, httpContext), factoryContext.Metadata);
}
@@ -187,7 +187,8 @@ public static partial class RequestDelegateFactory
return context;
}
- private static Func<object?, HttpContext, Task> CreateTargetableRequestDelegate(MethodInfo methodInfo, Expression? targetExpression, FactoryContext factoryContext)
+ private static Func<object?, HttpContext, Task> CreateTargetableRequestDelegate(MethodInfo methodInfo, Expression? targetConvertMethod,
+ FactoryContext factoryContext, object? targetInstance = null)
{
// Non void return type
@@ -211,7 +212,7 @@ public static partial class RequestDelegateFactory
// CreateArguments will add metadata inferred from parameter details
var arguments = CreateArguments(methodInfo.GetParameters(), factoryContext);
var returnType = methodInfo.ReturnType;
- factoryContext.MethodCall = CreateMethodCall(methodInfo, targetExpression, arguments);
+ factoryContext.MethodCall = CreateMethodCall(methodInfo, targetConvertMethod, arguments);
// Add metadata provided by the delegate return type and parameter types next, this will be more specific than inferred metadata from above
AddTypeProvidedMetadata(methodInfo, factoryContext.Metadata, factoryContext.ServiceProvider);
@@ -223,11 +224,11 @@ public static partial class RequestDelegateFactory
// return type associated with the request to allow for the filter invocation pipeline.
if (factoryContext.Filters is { Count: > 0 })
{
- var filterPipeline = CreateFilterPipeline(methodInfo, targetExpression, factoryContext);
+ var filterPipeline = CreateFilterPipeline(methodInfo, targetConvertMethod, factoryContext, targetInstance);
Expression<Func<RouteHandlerInvocationContext, ValueTask<object?>>> invokePipeline = (context) => filterPipeline(context);
returnType = typeof(ValueTask<object?>);
// var filterContext = new RouteHandlerInvocationContext(httpContext, new[] { (object)name_local, (object)int_local });
- // invokePipeline.Invoke(filterContext);
+ // invokePipeline.Invoke(target, filterContext);
factoryContext.MethodCall = Expression.Block(
new[] { InvokedFilterContextExpr },
Expression.Assign(
@@ -250,24 +251,38 @@ public static partial class RequestDelegateFactory
return HandleRequestBodyAndCompileRequestDelegate(responseWritingMethodCall, factoryContext);
}
- private static RouteHandlerFilterDelegate CreateFilterPipeline(MethodInfo methodInfo, Expression? target, FactoryContext factoryContext)
+ private static RouteHandlerFilterDelegate CreateFilterPipeline(MethodInfo methodInfo, Expression? targetConvertMethod,
+ FactoryContext factoryContext, object? targetInstance)
{
Debug.Assert(factoryContext.Filters is not null);
- // httpContext.Response.StatusCode >= 400
- // ? Task.CompletedTask
- // : handler((string)context.Parameters[0], (int)context.Parameters[1])
+ // if (httpContext.Response.StatusCode >= 400)
+ // {
+ // return Task.CompletedTask;
+ // }
+ // if (inline-delegate) // code generation time check
+ // {
+ // var target;
+ // target = targetInstance;
+ // return Convert(target, compilerType).handler((string)context.Parameters[0], (int)context.Parameters[1]);
+ // }
+ // else
+ // {
+ // return handler((string)context.Parameters[0], (int)context.Parameters[1]);
+ // }
var filteredInvocation = Expression.Lambda<RouteHandlerFilterDelegate>(
Expression.Condition(
Expression.GreaterThanOrEqual(FilterContextHttpContextStatusCodeExpr, Expression.Constant(400)),
CompletedValueTaskExpr,
Expression.Block(
new[] { TargetExpr },
+ Expression.Assign(TargetExpr, Expression.Constant(targetInstance)),
Expression.Call(WrapObjectAsValueTaskMethod,
- target is null
+ targetConvertMethod is null
? Expression.Call(methodInfo, factoryContext.ContextArgAccess)
- : Expression.Call(target, methodInfo, factoryContext.ContextArgAccess))
+ : Expression.Call(targetConvertMethod, methodInfo, factoryContext.ContextArgAccess))
)),
FilterContextExpr).Compile();
+
var routeHandlerContext = new RouteHandlerContext(
methodInfo,
new EndpointMetadataCollection(factoryContext.Metadata));
diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
index 5501077e54..6ef957f23a 100644
--- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
+++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
@@ -4579,6 +4579,46 @@ public class RequestDelegateFactoryTests : LoggedTest
}
[Fact]
+ public async Task RequestDelegateFactory_CanInvokeEndpointFilter_WithInlineDelegate()
+ {
+ // Arrange
+ var httpContext = CreateHttpContext();
+
+ var responseBodyStream = new MemoryStream();
+ httpContext.Response.Body = responseBodyStream;
+
+ httpContext.Request.Query = new QueryCollection(new Dictionary<string, StringValues>
+ {
+ ["name"] = "TestName"
+ });
+
+ // Act
+ var factoryResult = RequestDelegateFactory.Create((string name) =>
+ {
+ return $"Hello, {name}!";
+ },
+ new RequestDelegateFactoryOptions()
+ {
+ RouteHandlerFilterFactories = new List<Func<RouteHandlerContext, RouteHandlerFilterDelegate, RouteHandlerFilterDelegate>>()
+ {
+ (routeHandlerContext, next) =>
+ {
+ return async (context) =>
+ {
+ return await next(context);
+ };
+ },
+ }
+ });
+ var requestDelegate = factoryResult.RequestDelegate;
+ await requestDelegate(httpContext);
+
+ // Assert
+ var responseBody = Encoding.UTF8.GetString(responseBodyStream.ToArray());
+ Assert.Equal("Hello, TestName!", responseBody);
+ }
+
+ [Fact]
public void Create_AddsDelegateMethodInfo_AsMetadata()
{
// Arrange