Repository navigation
Remove RequiresDynamicCode from Microsoft.Extensions.DependencyInjection #79286
Description
Activity
The check is enabled by default when PublishAot=true.
Please don't break other AOT scenarios
We're trying to make AOT scenarios work, not break them 😄
Reacted by Eric Erhardt and Joe4evrPlease don't break other AOT scenarios
I definitely don't intend to break existing AOT scenarios. For iOS and Android, I don't believe they are currently using the
<PublishAot>true</PublishAot>MSBuild property. @jonathanpeppers @rolfbjarne - can you confirm?But if they are, and need this functionality turned off, they will be able to disable this property by default, even when
PublishAot=true.We don't set
PublishAotoutside of Native AOT. It has other SDK behaviors attached to it that would not be applicable outside Native AOT (e.g. it gates the RequiresDynamicCode analyzer). There was a discussion around using this elsewhere in dotnet/sdk#25392, but it didn't come through.If we ever want to have this property mean something else than Native AOT, adjusting this feature flag would be just one of the many other things in the SDK that need adjusting.
Right now PublishAot means "publish with the limitations (and optimization opportunities) that apply to Native AOT" and it doesn't have a mapping to a mode of the Mono runtime. It could in the future.
Reacted by Eric ErhardtFor platforms running Mono,
$(RunAOTCompilation)is used instead:runtime/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in
Line 57 in 41ae1ae
<Import Condition="'$(TargetsCurrent)' == 'true' and '$(RunAOTCompilation)' == 'true' and ('$(UsingBrowserRuntimeWorkload)' == 'true' or '$(UsingMobileWorkload)' == 'true')" Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task" /> I don't know of anything Mono-related that uses
$(PublishAot)yet. @radical might know for sure.I don't know of anything Mono-related that uses $(PublishAot) yet.
Yep, that's my understanding too.
- ghost addedin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
on Dec 9, 2022 Right now PublishAot means "publish with the limitations (and optimization opportunities) that apply to Native AOT" and it doesn't have a mapping to a mode of the Mono runtime. It could in the future.
For iOS, tvOS and partially Mac Catalyst, AOT is on by default, and tweaked/turned off (kind of) with
UseInterpreterinstead.We will resolve the 2 NativeAOT warnings above by adding a runtime check that is behind a new AppContext switch
Microsoft.Extensions.DependencyInjection.VerifyAotCompatibility.Might I suggest
Microsoft.Extensions.DependencyInjection.VerifyNativeAotCompatibilityinstead? Since this seems limited to NativeAOT in particular.Since this seems limited to NativeAOT in particular.
The impact is not limited to native AOT. The patterns flagged by these checks are going to be slow on platforms without a JIT, like iOS, etc.
@eerhardt as a datapoint I've used dependency injection as a simple extensibility mechanism where I'm injecting an IEnumerable into a service where there has been multiple T's also injected into the DI infra:
Example:
Registration: https://github.com/Azure/azure-sdk-tools/blob/28c8db9782063964505d875bbc9d161baf930ab1/tools/pipeline-witness/Azure.Sdk.Tools.PipelineWitness/Startup.cs#L71
Injection Site: https://github.com/Azure/azure-sdk-tools/blob/28c8db9782063964505d875bbc9d161baf930ab1/tools/pipeline-witness/Azure.Sdk.Tools.PipelineWitness/Services/FailureAnalysis/FailureAnalyzer.cs#L13I'd want to make sure IEnumerable injection for reference types would still work. From your issue description it wasn't entirely clear whether you saw this as a valid scenario.
@davidfowl has informed me that IEnumerable where T is a reference type would be supported.
Correct - reference types are still 100% supported. From the proposal above:
The runtime check ensures the Types being used with Enumerable and Open Generic services are only Reference Types. If an application tries to create an Enumerable or Closed Generic service of a ValueType, DependencyInjection will throw an exception.
Reacted by Mitch Denny- added a commit that references this issue
on Jan 9, 2023 Might I suggest Microsoft.Extensions.DependencyInjection.VerifyNativeAotCompatibility instead? Since this seems limited to NativeAOT in particular.
I have changed the proposal to be based off the DynamicCodeSupport feature switch instead of adding one specific for DependencyInjection.
- added a commit that references this issue
on Jan 10, 2023 - ghost removedin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
on Jan 10, 2023 I've been considering contributing to the DI library. It seems to me a like a code generator would be a good solution for this. It may require people modify their code in how they define their DI. But I'm curious, is anyone currently considering/working on this?
It seems to me a like a code generator would be a good solution for this. It may require people modify their code in how they define their DI. But I'm curious, is anyone currently considering/working on this?
I've been considering contributing to the DI library. It seems to me a like a code generator would be a good solution for this. It may require people modify their code in how they define their DI. But I'm curious, is anyone currently considering/working on this?
With the current pattern, a code generator doesn't work well because you can't generate "efficient" code unless you have the full closure of dependencies at compile time. That isn't possible today because the service collection is a runtime list of dependencies which makes this sort of code generation hard.
We're don't have plans to re-design how dependencies are registered (like jab does), at least not as part of the core container implementation.
- ghost locked as resolved and limited conversation to collaborators
on Mar 1, 2023
In .NET 7, with #73829, we annotated Microsoft.Extensions.DependencyInjection as RequiresDynamicCode because it supports enumerable and generic servcies with ValueTypes. When using DI with ValuesTypes, the array and generic code might not be available.
In .NET 8 we need a better approach in order to support applications that use DependencyInjection and publish for NativeAOT. DependencyInjection needs to have reliable behavior before and after publishing for NativeAOT. The application can't work successfully at development-time, but then fail after publishing with
PublishAot=true.Problem
The good thing, there are only limited scenarios where DependencyInjection needs to use dynamic code. And these scenarios are not used very often in real-world applications.
Proposal
The proposed approach is similar to how we solved trim-compatibility with DependencyInjection in #55102.
We will resolve the 2 NativeAOT warnings above by adding a runtime check that is behind a new AppContext switch
Microsoft.Extensions.DependencyInjection.VerifyAotCompatibility. The runtime check ensures the Types being used with Enumerable and Open Generic services are only Reference Types. If an application tries to create an Enumerable or Closed Generic service of a ValueType, DependencyInjection will throw an exception. The check is enabled by default whenPublishAot=true.The recommendation for applications that want to publish for NativeAOT is to put
<PublishAot>true</PublishAot>in their .csproj. That way they get the appropriate analyzers and runtime behaviors during development-time, i.e. F5 in VS ordotnet runfrom the command line. Applications using the incompatible features above will be broken at development time if the app is intended to be published for AOT. This will give the app developer indication their application won't work after publishing for NativeAOT as well.cc @davidfowl @halter73 @JamesNK @MichalStrehovsky @agocke @vitek-karas @jkotas