dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.07k forks source link

Retrieving assembly version or other related info without reflection #39555

Open Evangelink opened 7 months ago

Evangelink commented 7 months ago

Is your feature request related to a problem? Please describe.

To support native AOT, it is required to remove calls to reflection APIs. A common scenario of reflection is to try to retrieve assembly info (usually versions but it could be more). To overcome this limitation, there are many tools that are being published, most of them relying on source generators. For example, https://github.com/devlooped/ThisAssembly or https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.cs?rgh-link-date=2024-03-12T10%3A46%3A37Z.

As .NET SDK produces the AssemblyInfo.cs, I was wondering if there was any consideration for a common (out-of-the-box) solution for that.

Describe the solution you'd like

I would like an easy way to retrieve these metadata without adding extra dependency or without having to maintain the source generator on my own.

Additional context

cc @MichalStrehovsky

baronfel commented 7 months ago

Other prior art is the AssemblyInfo module in FAKE - it also used to generate an F# module with values containing this data. This seems like a pretty easy addition to the existing AssemblyInfo generation, though it would need to be behind another flag in case users wanted to turn it off.

MichalStrehovsky commented 7 months ago

To support native AOT, it is required to remove calls to reflection APIs. A common scenario of reflection is to try to retrieve assembly info (usually versions but it could be more)

I don't understand this part. Reflecting on assembly attributes works and triggers no trimming/aot warnings. What's the underlying reason for a new mechanism?

vitek-karas commented 7 months ago

Another option is https://learn.microsoft.com/en-us/dotnet/standard/assembly/inspect-contents-using-metadataloadcontext. This allows opening assemblies at runtime and inspecting their metadata without loading them into the runtime. This is not a reflection and should work just fine even in trimmed/AOT application. All it does is open the assembly as a file, read its content and expose it through an object model.

Evangelink commented 7 months ago

I don't understand this part. Reflecting on assembly attributes works and triggers no trimming/aot warnings. What's the underlying reason for a new mechanism?

I'll redo some experiment but I recall that last year this wasn't working.

MichalStrehovsky commented 7 months ago

I don't understand this part. Reflecting on assembly attributes works and triggers no trimming/aot warnings. What's the underlying reason for a new mechanism?

I'll redo some experiment but I recall that last year this wasn't working.

If this is for MSTest, I know that MSTest at some point used the undocumented/unsupported/no-plans-to-productize IlcDisableReflection mode. Reflecting on attributes doesn't not work in that mode, because nothing works in that mode. Nobody should be using that switch, it's for developmental purposes in the dotnet/runtime repo. I see testfx repo now has no references to that switch and that's good.

I don't think you need the feature this issue asks for.

Evangelink commented 7 months ago

I confirm this is working, I still believe it would be good to have something compile time rather than reflection based but feel free to close this ticket if you don't think this is a good improvement.

MichalStrehovsky commented 7 months ago

I confirm this is working, I still believe it would be good to have something compile time rather than reflection based but feel free to close this ticket if you don't think this is a good improvement.

I agree it could be useful - it just shouldn't be motivated by native AOT IlcDisableReflection mode.

LevYas commented 1 month ago

BTW despite having "Reflection" in the full type name, this works well in win-x64 AOTed application:

Version? version = System.Reflection.AssemblyName.GetAssemblyName("MyApp.dll").Version;

But that's version-only, of course.