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

Make Environment.Version return the actual runtime version #3271

Closed
steveharter opened this issue Aug 12, 2018 · 11 comments
Closed

Make Environment.Version return the actual runtime version #3271

steveharter opened this issue Aug 12, 2018 · 11 comments
Assignees
Labels
area-Host enhancement Product code improvement that does NOT require public API changes/additions
Milestone

Comments

@steveharter
Copy link
Member

@davidfowl commented on Mon Jul 16 2018

Today on a .NET Core 2.1.0 project printing Environment.Version prints out 4.0.30319.42000 which is a hard coded constant in the runtime https://github.com/dotnet/coreclr/blob/ce0a2617d40bc217b8e0a2137e340afe585afcb1/src/System.Private.CoreLib/src/System/Environment.cs#L277. This should print out the actual runtime version based on the policy applied by the host (like 2.1.1 if that's what runtime version is actually being used).

This also needs to be used as the version logged into the event log when there's an unhandled exception reported by the runtime. Today is a bogus version which isn't very useful.


@weshaggard commented on Mon Jul 23 2018

Today we don't have the "marketing version" (i.e. 2.1.1) embedded anywhere that we can consume so the best we could really do would be to return the file version of corelib.


@jkotas commented on Mon Jul 23 2018

The host knows this version - it can pass it to the runtime as key-value pair.


@weshaggard commented on Mon Jul 23 2018

The host knows this version - it can pass it to the runtime as key-value pair.

I assume it only knows it for applications running on the shared framework correct? What should we return for standalone applications?


@jkotas commented on Mon Jul 23 2018

All applications have it in .deps.json file.


@weshaggard commented on Mon Jul 23 2018

I assume you are referring to the package version for Microsoft.NETCore.App (or runtime.[rid].Microsoft.NETCore.App) then? If so yes that may work for now but that may not be in the deps file in the future but we could probably ensure some version remains for this purposes.


@abbotware commented on Mon Jul 23 2018

I've been looking for away to get the RuntimeFrameworkVersion, so I tried all the API's that I could find (#31249) and none seemed to return anything useful - Any programmatic way to get the 'marketing version' would be good enough for me.

@weshaggard is there is a 1:1 mapping for 'corelib version' to 'marketing version' ? If yes, then could a lookup table be constructed?

Regarding versions returned from API calls, I am kinda curious though why the difference in System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription: .NET Core 4.6.26614.01 and Environment.Version: 4.0.30319.42000

If one of those could be used to map back to the RuntimeFrameworkVersion, then there is at least a workaround for now?


@davidfowl commented on Tue Jul 24 2018

The host needs to pass the value to the runtime, the property would then read an AppContext property (or something similar) to get the actual version.

The host already does this for the deps file path in order to pass it to the DependencyModel API. https://github.com/dotnet/core-setup/blob/84fa44f892b42ad9235e4ecb756975d8c8f46f1f/src/corehost/cli/hostpolicy.cpp#L104

We just need to do this for the version as well.


@weshaggard commented on Tue Jul 24 2018

@weshaggard is there is a 1:1 mapping for 'corelib version' to 'marketing version' ? If yes, then could a lookup table be constructed?

Yes the corelib version is 1:1 with the marketing version but doesn't exactly match it. If you workaround this for now you can get the version of corelib the same way we do for FrameworkDescription https://github.com/dotnet/corefx/blob/master/src/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.cs#L28.

@davidfowl I agree the host can pass the value to the runtime it is just a matter of how it gets it in the various cases as well as what this API would do for custom hosts. We have to cover all the cases.


@davidfowl commented on Tue Jul 24 2018

We have to cover all the cases.

Sure, just make it a contract. We look at a specific AppContext variable which is controlled by the host. In absence of that, we show something that doesn't mean much to you (the CLR file version or something).


@steveharter commented on Tue Jul 24 2018

Talked to @davidfowl a bit. I think the most straightforward way to do this is for the hostpolicy to add a couple AppContext\AppDomain variables like "FRAMEWORK_NAMES" and "FRAMEWORK_VERSIONS". They would list each framework and found\actual version (not requested version) separated by a delimiter.

We already do similar things with "FX_DEPS_FILE" that is picked up later by the CLI.

This information could we wrapped by a managed class in the future (Environment or otherwise).


@steveharter commented on Tue Jul 24 2018

Adding a "FRAMEWORK_NAMES" and "FRAMEWORK_VERSIONS" would not work for standalone; we would need a mapping from deps.json version as explained earlier or some other mechanism depending on what info we want


@steveharter commented on Tue Jul 24 2018

Overlaps a bit with https://github.com/dotnet/core-setup/issues/4112 for logging this information


@abbotware commented on Tue Jul 24 2018

@steveharter does 'standalone' = 'self contained deployment' (SCD) ? (In my case I am using an Ubuntu SNAP to deploy .Net Core + my App + Native libs on Linux)


@davidfowl commented on Tue Jul 24 2018

@weshaggard @jkotas If we change this property to be useful does that count as a breaking change? Specifically because it would go backwards?


@weshaggard commented on Tue Jul 24 2018

@weshaggard @jkotas If we change this property to be useful does that count as a breaking change? Specifically because it would go backwards?

Every change is a breaking change :) however if we don't have any evidence that it will break people then we will assume it is not a breaking change. If enough folks get broken then we may change our mind about how we fix it.


@steveharter commented on Tue Jul 24 2018

does 'standalone' = 'self contained deployment' (SCD) ? (In my case I am using an Ubuntu SNAP to deploy .Net Core + my App + Native libs on Linux)

Yes.

From the host perspective, the easiest implementation for both self-contained and framework-dependent would be to simply add a "FX_DEPS_FILES" context variable, similar to existing "FX_DEPS_FILE", but lists the path to the app's deps.json, every framework deps.json and perhaps those specified by additional-deps as well. For self-contained, there would only be one deps.json.

Then the managed layer would need to read each deps file and use a json parser (probably just use DependencyModel like this) to obtain the desired framework(s) by name and report back on the version.

Besides being simpler for the host, an advantage would also allow the managed layer to report on any types of other dependencies, including non-frameworks, assembly versions, etc if those were useful for logging.

The disadvantage is that it creates a dependency on the deps.json for the managed layer, which can change over time.

When we decide on a plan, I'll move this issue over to core-setup.


@jkotas commented on Wed Jul 25 2018

Then the managed layer would need to read each deps file and use a json parser (probably just use DependencyModel like this)

I do not think we would want to create dependency from Environment.Version (very low-level API) to DepenendencyModel.


@davidfowl commented on Wed Jul 25 2018

I'd prefer we just set the version data direction in the host properties instead of using the deps file. Agree with @jkotas, we can't take a dependency in mscorlib on deps.json. It should be host agnostic.

@steveharter steveharter self-assigned this Aug 12, 2018
@davidfowl
Copy link
Member

One challenge I just realized exists with using Environment.Version is the fact that it won’t support pre-releases since it’s a Version (not semantic version)

@steveharter
Copy link
Member Author

steveharter commented Aug 13, 2018

From the host side, would implementing just (1) below work? See also additional options (2) and (3).

Minimal implementation:
1) Expose FX_FILE_VERSION appdomain variable which is the fileVersion of mscorlib.dll, as taken from the deps.json of the app (self-contained) or Microsoft.NETCore.App (framework-dependent).

This will work for both self-contained and framework-dependent applications.

Using mscorelib.dll fileVersion is what Environment.Version is based on but now hard-codes (immutable and currently never changes). However FX_FILE_VERSION would be based on the actual fileVersion - e.g. for 2.1.2 it would be "4.6.26629.1" and for 2.1.3, it would be "4.6.26726.4". Note that assemblyVersion doesn't change from release to release so we use fileVersion instead.

If we want a nice "product" version (e.g. 3.0.0-preview1) we could either assume a mapping from FX_FILE_VERSION to product version that we could either doc or implement somewhere, or we could expose another appdomain variable that would only work with framework-dependent:
2) Optionally expose FX_PRODUCT_VERSION appdomain variable to return the version of Microsoft.NETCore.App (which is the "lowest" framework). E.g. "3.0.0-preview1".

Finally if we want all framework versions:
3) Optionally expose "FRAMEWORK_NAMES" and "FRAMEWORK_VERSIONS" as previously mentioned.

@jkotas
Copy link
Member

jkotas commented Aug 13, 2018

which is the fileVersion of mscorlib.dll, as taken from the deps.json of the app

I do not think we want this version. It is the version that the app was built against. I think we want the version that the app is actually running on.

@steveharter
Copy link
Member Author

which is the fileVersion of mscorlib.dll, as taken from the deps.json of the app

I do not think we want this version. It is the version that the app was built against. I think we want the version that the app is actually running on.

For self-contained this should be the same; I'm assuming that to get a newer version of the coreclr requires the app to be re-built\published which will re-generate the deps.json.

@davidfowl
Copy link
Member

I do not think we want this version. It is the version that the app was built against. I think we want the version that the app is actually running on.

Yes Yes Yes.

For self-contained this should be the same; I'm assuming that to get a newer version of the coreclr requires the app to be re-built\published which will re-generate the deps.json.

We want the resolved version that the host policy ended up running on. Not build time dependencies. Not the file version but the actual runtime version that shows up when you dotnet --info

@steveharter
Copy link
Member Author

I think there is a misunderstanding.

For framework-dependent, we would obtain the mscorlib.dll fileVersion from the Microsoft.NETCore.App.deps.json that we're running against. Yes it was assigned during build-time, but the set of files for a given framework version is immutable.

For self-contained, the app is running on the framework version it was built against. @dsplaisted is the app's deps.json updated with the appropriate fileVersion\assemblyVersion of framework assemblies when the app is re-built and automatically taking the latest framework patch? (I assume it is).

The exception is the "hammer" servicing, which we haven't used yet.

Note on Unix, since there isn't really a OS-level "file version" we would have to rely on the deps.json information, unless we want to crack open the assembly at run-time to look for the attribute but this has it's own set of technical issues when done from the host (before the CLR is initialized). Thus the CLR would likely need to do it, not the host.

@steveharter
Copy link
Member Author

steveharter commented Aug 14, 2018

Also feature (1) asserts a "minimum" implementation (exposing fileVersion of mscorlib.dll) since the runtime version (e.g. "3.0.0-preview1") could be inferred from this, and that is what Environment.Version is based on (used to anyway, before it became hard-coded).

There are also options (2) and (3) above that can return the more easily consumable runtime versions, but that wouldn't work for self-contained until someone writes the mapping that would be needed in (1), which is mapping fileVersion(mscorlib.dll) -> frameworkVersion(Microsoft.NETCore.App)

@steveharter
Copy link
Member Author

Another option to consider, if we require the nice "framework version" for both standalone and self-contained would be to add that version information to the app's runtimeconfig.json for self-contained since today there is no framework reference (since it's "standalone" and doesn't need to look up the shared runtime).

That would require some tooling changes and a way to add that information to runtime.config without making the standalone app turn into framework-dependent, because the raw presence of the framework information today makes the app use the shared framework.

@jkotas
Copy link
Member

jkotas commented Aug 14, 2018

If we wanted to return CoreLib file version, we (or anybody else) can just do that. There is no cooperation with the host required. CoreLib is always opened by the runtime. The problem with CoreLib file version is that it is a useless piece of information on its own. As you have pointed out, you have to have infinitely growing table to map it to the netcoreapp version that you can reason about.

For self-contained, the app is running on the framework version it was built against.

For self-contained apps, .deps.json has Microsoft.NETCore.App version that the app is bundled with (e.g. Microsoft.NETCore.App/2.1.2).

@steveharter
Copy link
Member Author

steveharter commented Aug 14, 2018

Yes for self-contained we can read the deps.json for Microsoft.NETCore.App version, which today is a package version but should match the actual framework version. However if we want the versions from all frameworks (option 3) then that wouldn't work since we wouldn't want to "hard-code" the various framework package names in the host.

So would just option (2) work:
(2) FX_PRODUCT_VERSION appdomain variable to return the version of Microsoft.NETCore.App. E.g. "3.0.0-preview1".

For framework-dependent, we just get the version that we are using. For self-contained, we get the version by looking for the version specified by "Microsoft.NETCore.App" in the app's deps.json file.

Whether it is exposed through a managed API is TBD. We can't use Environment.Version for compat, plus we need a string not a System.Version type.

@steveharter
Copy link
Member Author

I have an implementation of (2) at dotnet/core-setup#4470

@msftgits msftgits transferred this issue from dotnet/core-setup Jan 30, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 30, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Host enhancement Product code improvement that does NOT require public API changes/additions
Projects
None yet
Development

No branches or pull requests

4 participants