-
Notifications
You must be signed in to change notification settings - Fork 10.4k
[AOT] Add expression free request filter pipeline for RequestDelegate #46020
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7c05d28
2144c91
9164a7e
25a030d
fc87c7c
2c77699
690b124
29ede70
67a3392
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Diagnostics; | ||
using System.Text.Json.Serialization.Metadata; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Http.Json; | ||
using Microsoft.AspNetCore.Internal; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.Routing; | ||
|
||
internal static class RequestDelegateFilterPipelineBuilder | ||
{ | ||
// Due to https://github.com/dotnet/aspnetcore/issues/41330 we cannot reference the EmptyHttpResult type | ||
// but users still need to assert on it as in https://github.com/dotnet/aspnetcore/issues/45063 | ||
// so we temporarily work around this here by using reflection to get the actual type. | ||
private static readonly object? EmptyHttpResultInstance = Type.GetType("Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult, Microsoft.AspNetCore.Http.Results")?.GetProperty("Instance")?.GetValue(null, null); | ||
|
||
public static RequestDelegate Create(RequestDelegate requestDelegate, RequestDelegateFactoryOptions options) | ||
{ | ||
Debug.Assert(options.EndpointBuilder != null); | ||
|
||
var serviceProvider = options.ServiceProvider ?? options.EndpointBuilder.ApplicationServices; | ||
var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? new JsonOptions(); | ||
var jsonSerializerOptions = jsonOptions.SerializerOptions; | ||
|
||
var factoryContext = new EndpointFilterFactoryContext | ||
{ | ||
MethodInfo = requestDelegate.Method, | ||
ApplicationServices = options.EndpointBuilder.ApplicationServices | ||
}; | ||
var jsonTypeInfo = (JsonTypeInfo<object>)jsonSerializerOptions.GetReadOnlyTypeInfo(typeof(object)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this work with source generation, if we always get the JsonTypeInfo for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is weird, but OK I guess. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very weird. |
||
|
||
EndpointFilterDelegate filteredInvocation = async (EndpointFilterInvocationContext context) => | ||
{ | ||
Debug.Assert(EmptyHttpResultInstance != null, "Unable to get EmptyHttpResult instance via reflection."); | ||
if (context.HttpContext.Response.StatusCode < 400) | ||
{ | ||
await requestDelegate(context.HttpContext); | ||
} | ||
return EmptyHttpResultInstance; | ||
}; | ||
|
||
var initialFilteredInvocation = filteredInvocation; | ||
for (var i = options.EndpointBuilder.FilterFactories.Count - 1; i >= 0; i--) | ||
{ | ||
var currentFilterFactory = options.EndpointBuilder.FilterFactories[i]; | ||
filteredInvocation = currentFilterFactory(factoryContext, filteredInvocation); | ||
} | ||
|
||
// The filter factories have run without modifying per-request behavior, we can skip running the pipeline. | ||
if (ReferenceEquals(initialFilteredInvocation, filteredInvocation)) | ||
{ | ||
return requestDelegate; | ||
} | ||
|
||
return async (HttpContext httpContext) => | ||
{ | ||
var obj = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, new object[] { httpContext })); | ||
JamesNK marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (obj is not null) | ||
{ | ||
await ExecuteHandlerHelper.ExecuteReturnAsync(obj, httpContext, jsonSerializerOptions, jsonTypeInfo); | ||
} | ||
}; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.