diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index f30dbe63ca10..159982900eda 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -543,6 +543,11 @@ private static Expression MapHandlerReturnTypeToValueTask(Expression methodCall, } } + if (returnType.IsValueType) + { + return Expression.Call(WrapObjectAsValueTaskMethod, Expression.Convert(methodCall, typeof(object))); + } + return Expression.Call(WrapObjectAsValueTaskMethod, methodCall); } diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs new file mode 100644 index 000000000000..894abb121049 --- /dev/null +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.InternalTesting; + +namespace Microsoft.AspNetCore.Routing.Internal; + +public partial class RequestDelegateFactoryTests : LoggedTest +{ + public static object[][] ValueTypeReturningDelegates => + [ + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 'b')], + [(Func)((HttpContext httpContext) => true)], + [(Func)((HttpContext httpContext) => 4.2f)], + [(Func)((HttpContext httpContext) => 4.2)], + [(Func)((HttpContext httpContext) => 4.2m)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)] + ]; + + [Theory] + [MemberData(nameof(ValueTypeReturningDelegates))] + public void Create_WithEndpointFilterOnBuiltInValueTypeReturningDelegate_Works(Delegate @delegate) + { + var invokeCount = 0; + + RequestDelegateFactoryOptions options = new() + { + EndpointBuilder = CreateEndpointBuilderFromFilterFactories( + [ + (routeHandlerContext, next) => + { + invokeCount++; + return next; + }, + (routeHandlerContext, next) => + { + invokeCount++; + return next; + }, + ]), + }; + + var result = RequestDelegateFactory.Create(@delegate, options); + Assert.Equal(2, invokeCount); + } + + public static object[][] NullableValueTypeReturningDelegates => + [ + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 'b')], + [(Func)((HttpContext httpContext) => true)], + [(Func)((HttpContext httpContext) => 4.2f)], + [(Func)((HttpContext httpContext) => 4.2)], + [(Func)((HttpContext httpContext) => 4.2m)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)], + [(Func)((HttpContext httpContext) => 42)] + ]; + + [Theory] + [MemberData(nameof(NullableValueTypeReturningDelegates))] + public void Create_WithEndpointFilterOnNullableBuiltInValueTypeReturningDelegate_Works(Delegate @delegate) + { + var invokeCount = 0; + + RequestDelegateFactoryOptions options = new() + { + EndpointBuilder = CreateEndpointBuilderFromFilterFactories( + [ + (routeHandlerContext, next) => + { + invokeCount++; + return next; + }, + (routeHandlerContext, next) => + { + invokeCount++; + return next; + }, + ]), + }; + + var result = RequestDelegateFactory.Create(@delegate, options); + Assert.Equal(2, invokeCount); + } +}