Skip to content
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

MissingMethodException thrown in native AoT application using AddStandardResilienceHandler() with .NET 9 preview.2 #105034

Closed
martincostello opened this issue Mar 23, 2024 · 13 comments · Fixed by #105133

Comments

@martincostello
Copy link
Member

martincostello commented Mar 23, 2024

Description

I've been testing an application of mine which is a native AoT application deployed to AWS Lambda with .NET 9. As part of the testing I wanted to try out the new JsonSerializerOptions.AllowOutOfOrderMetadataProperties property to support using polymorphism with the JSON serialization for types used by the AWS Alexa skills API.

Having resolved an issue with getting that to work properly, I've run into a new issue where trying to resolve an HttpClient with HttpClientFactory when AddStandardResilienceHandler() has been associated with all instances causes a MissingMethodException to be thrown (martincostello/alexa-london-travel#1116 (comment)).

System.MissingMethodException: Constructor on type 'Polly.Registry.ResiliencePipelineRegistryOptions`1[Microsoft.Extensions.Http.Resilience.Internal.HttpKey]' not found.
   at System.Activator.CreateInstance[T]() + 0x88
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String) + 0x38
   at Microsoft.Extensions.Options.UnnamedOptionsManager`1.get_Value() + 0xbc
   at Polly.PollyServiceCollectionExtensions.<>c__6`1.<AddResiliencePipelineRegistry>b__6_0(IServiceProvider serviceProvider) + 0x3c
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite, RuntimeResolverContext) + 0x1c
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite, RuntimeResolverContext) + 0x74
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite, TArgument) + 0xb8
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite, ServiceProviderEngineScope) + 0x34
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier) + 0x130\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope) + 0x384
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider, Type) + 0xc8
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider) + 0x30
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite, RuntimeResolverContext) + 0x1c
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite, RuntimeResolverContext) + 0x74
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite, TArgument) + 0xb8
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite, ServiceProviderEngineScope) + 0x34
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier) + 0x130\n   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope) + 0x384
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider, Type) + 0xc8\n   at Microsoft.Extensions.DependencyInjection.ResilienceHttpClientBuilderExtensions.CreatePipelineSelector(IServiceProvider, String) + 0x48
   at Microsoft.Extensions.DependencyInjection.ResilienceHttpClientBuilderExtensions.<>c__DisplayClass6_0.<AddResilienceHandler>b__0(IServiceProvider serviceProvider) + 0x20
   at Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.<>c__DisplayClass3_0.<AddHttpMessageHandler>b__1(HttpMessageHandlerBuilder) + 0x24
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.<>c__DisplayClass17_0.<CreateHandlerEntry>g__Configure|0(HttpMessageHandlerBuilder) + 0x78
   at Microsoft.Extensions.Http.MetricsFactoryHttpMessageHandlerFilter.<>c__DisplayClass2_0.<Configure>b__0(HttpMessageHandlerBuilder) + 0x28
   at Microsoft.Extensions.Http.LoggingHttpMessageHandlerBuilderFilter.<>c__DisplayClass6_0.<Configure>b__0(HttpMessageHandlerBuilder) + 0x30
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry(String) + 0x258\n   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode) + 0x50
--- End of stack trace from previous location ---
   at System.Lazy`1.CreateValue() + 0xdc
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String) + 0x58
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String) + 0x2c
   at Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddTransientHelper[TClient](IServiceProvider, IHttpClientBuilder) + 0x3c\n   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite, RuntimeResolverContext) + 0x1c
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite, RuntimeResolverContext) + 0x20
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite, TArgument) + 0x154
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x88
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite, RuntimeResolverContext) + 0x20
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite, TArgument) + 0x154
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite, ServiceProviderEngineScope) + 0x34
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope) + 0x344
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider, Type) + 0xc8
   at MartinCostello.LondonTravel.Skill.IntentFactory.Create(Intent) + 0x278
   at MartinCostello.LondonTravel.Skill.AlexaSkill.<OnIntentAsync>d__5.MoveNext() + 0x38
--- End of stack trace from previous location ---
   at MartinCostello.LondonTravel.Skill.FunctionHandler.<HandleRequestAsync>d__4.MoveNext() + 0x198

It could be that this is a trimmer issue (or something wrong in my code that wasn't wrong before), but as the Microsoft.Extensions.Http.Resilience.Internal.HttpKey type is defined in this repo and removing the call to AddStandardResilienceHandler() (see martincostello/alexa-london-travel@e3e7de1) fixes the issue, I figured this was the best first port of call.

Reproduction Steps

I'll try and create a branch with an easy-to-execute local repro later, but the code with the issue is at this commit: martincostello/alexa-london-travel@50eb0a2.

1. Clone martincostello/alexa-london-travel@75e5c8b
2. Run build.ps1 in the root directory of the repository.

  1. Clone https://github.com/martincostello/dotnet-extensions-5062-repro
  2. Run the following commands from the root of the repository:
    dotnet publish
    ./artifacts/publish/dotnet-extensions-5062-repro/release/repro

Expected behavior

HttpClient requests using resilience are correctly resolved from DI and work as expected.

Actual behavior

A MissingMethodException is thrown from here:

https://github.com/dotnet/extensions/blob/16b40667278d24a23af0c839f4c277499b3fee19/src/Libraries/Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs#L80

Regression?

From .NET 8, yes.

Known Workarounds

None.

Configuration

  • .NET SDK 9.0.100-preview.2.24157.14
  • Microsoft.Extensions.Http.Resilience 9.0.0-preview.2.24157.4

Other information

No response

@martincostello martincostello added bug untriaged New issue has not been triaged by the area owner labels Mar 23, 2024
@martincostello martincostello changed the title MissingMethodException throw in native AoT application using AddStandardResilienceHandler() MissingMethodException thrown in native AoT application using AddStandardResilienceHandler() with .NET 9 preview.2 Mar 23, 2024
@martincostello
Copy link
Member Author

Whether it's a problem or not I don't know, but I tried to restore the functionality by adding the following to my project file and I get these errors:

<PropertyGroup>
  <TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
<ItemGroup>
  <TrimmerRootAssembly Include="Microsoft.Extensions.Http.Resilience" />
</ItemGroup>
  LondonTravel.Skill failed with errors (40.5s) → artifacts\bin\LondonTravel.Skill\release\LondonTravel.Skill.dll
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.WeightedGroupsRoutingOptions.Groups: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.WeightedGroupsRoutingOptions.Groups: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.UriEndpointGroup.Endpoints: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.UriEndpointGroup.Endpoints: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.OrderedGroupsRoutingOptions.Groups: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]
    ILC : Trim analysis error IL2026: Microsoft.Extensions.Http.Resilience.OrderedGroupsRoutingOptions.Groups: Using member 'System.ComponentModel.DataAnnotations.LengthAttribute.LengthAttribute(Int32,Int32)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved. [C:\Coding\martincostello\alexa-london-travel\src\LondonTravel.Skill\LondonTravel.Skill.csproj]

Looking at the code, the warnings are being suppressed using pragmas rather than attributes, so the trimmer can't reason about the intentional suppressions.

https://github.com/dotnet/extensions/blob/9f99a5835df88eb2b3c0444273a8e6f18c4eb27b/src/Libraries/Microsoft.Extensions.Http.Resilience/Routing/WeightedGroupsRoutingOptions.cs#L28-L37

@martincostello
Copy link
Member Author

I've also tried the following, but that doesn't seem to be working either:

<ItemGroup>
  <TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>
<linker>
  <assembly fullname="Microsoft.Extensions.Http.Resilience">
    <type fullname="Microsoft.Extensions.Http.Resilience.Internal.HttpKey" preserve="all" />
  </assembly>
  <assembly fullname="Polly.Core">
    <type fullname="Polly.Registry.ResiliencePipelineRegistryOptions`1" preserve="all" />
  </assembly>
</linker>

@martincostello
Copy link
Member Author

Still observing this issue with .NET 9 preview 3.

@martincostello
Copy link
Member Author

I've been able to reproduce this outside of my deployed AWS Lambda function using the new AoT support in MSTest here: martincostello/alexa-london-travel#1157

@martincostello
Copy link
Member Author

Minimal repro added here: https://github.com/martincostello/dotnet-extensions-5062-repro

@RussKie
Copy link
Member

RussKie commented Apr 18, 2024

@iliar-turdushev could you please have a look?

@martincostello
Copy link
Member Author

Re-tested with preview 4, still an issue.

@geeknoid geeknoid removed the untriaged New issue has not been triaged by the area owner label May 31, 2024
@martincostello
Copy link
Member Author

Still repros with .NET 9 preview 5.

@martincostello
Copy link
Member Author

Still an issue with .NET 9 preview 6.

@martincostello
Copy link
Member Author

@eerhardt @MichalStrehovsky Sorry to ping directly, but you're the two of the native AoT experts I know of.

It concerns me that this still isn't working, telling the trimmer to preserve the type doesn't seem to work #105034, and this issue has been open for nearly 4 months now and the .NET 9 release is starting to wrap up the previews.

Feels like either the fix should be trivial if it's here, or there's an issue in the trimmer itself. Either way I don't know enough in this area to resolve it myself, otherwise I'd have dug into it myself and offered a PR by now.

@MichalStrehovsky MichalStrehovsky transferred this issue from dotnet/extensions Jul 17, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jul 17, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Jul 17, 2024
@MichalStrehovsky
Copy link
Member

This looks like a native AOT bug. Moved this to dotnet/runtime.

@github-actions github-actions bot locked and limited conversation to collaborators Aug 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

5 participants