Update RequestDelegateGenerator to use interceptors compiler feature #48289
Labels
area-minimal
Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
feature-rdg
Milestone
The RequestDelegateGenerator currently takes advantage of overload resolution semantics to favor
Map
overloads that are generated at compile-time over those that are shipped in framework and use runtime code compilation.The compiler now has an "interceptors" feature which allows generating a method at compile time with an
InterceptsLocation
attribute that will indicate the generated method should be favored over an in-framework method invoked at a particular file-path, line number, and character.Note: to improve maintainability of the generator, moving forward all code will be emitted using the interceptors feature and we'll avoid using overload resolution semantics in the code gen. The intercepts feature is more explicit about which overloads are executed given a particular invocation which will make providing user support and debugging for this feature much easier. Going all in on one generation strategy will also reduce the burden of having to produce different kinds of overloads for different scenarios.
The following changes will need to be made to the code generation in reaction to this feature:
1. Generated
Map
definitions no longer need to be emitted in internal classAt the moment, we emit the compile-time generated
Map
definitions that are meant to override the in-framework ones into an internal namespace so they can participate in overload resolution.With interceptors, these definitions can be emitted into the
file private
class generated by the compiler which has the benefit of reducing pollution in the user's namespace.2. Generated
Map
definition no longer need to define strongly-typed delegate argumentCurrently, the compile-time generated
Map
definitions emit a definition with a delegate parameter that is strong-typed, as seen below, so that the generated overload is favored during overload resolution.With interceptors, we no longer need to strongly-type the
Delegate
parameter and do not need to provide theCallerLinePath
andCallerLineNumber
values into the compiler.3. Emit
InterceptsLocationAttribute
definition in generated codeThe interceptors implementation relies on an implementation of
InterceptsLocationAttribute
that is not yet defined in the core libraries. For now, this attribute will need to be emitted as afile private
type in the generated code:4. Remove reliance on Dictionary thunks
Currently, the RequestDelegate Generator maintains a dictionary that associates a
SourceKey
that references an endpoint with theMetadataPopulator
andRequestDelegateFactoryFunc
methods that are associated with it. This look up serves as a cache for endpoints that end up resolving to the same overload but have differing implementations.The
MetadataPopulator
andRequestDelegateFactoryFunc
can be inlined in the interceptorMap
method in this implementation to avoid the cost of dictionary lookup/strategy.This also has the benefit of making the code-gen logic much simpler since we have fewer
IncrementalValueProviders
to concatenate in the end when we construct the argument source.5. Update logic for casting
Delegate
into strongly-defined handler inside generated codeThe RequestDeelgateGenerator currently casts the generic
Delegate
provided in theRequestDelegateFactoryFunc
with an explicit cast like so:Due to a breaking change in the inferred type for method groups with lambdas in the new version of the compiler, we need to update the cast to use a delegate that passes through the default value into the conversion.
A prototype of this implementation can be found at this branch.
The text was updated successfully, but these errors were encountered: