First, let's see what happens when a portable .NET Core application runs through dotnet yourapp.dll :
- The muxer executable (
dotnet.exe in the windows) loads the version of the host raster converter ( hostfxr ) from the folder below host\fxr\ next to dotnet.exe . - The host architecture
yourapp.runtimeconfig.json looks at yourapp.runtimeconfig.json (or another file if configured using dotnet exec ) to find out which structure you are targeting. This retrieves the frame name ( Microsoft.NETCore.App ) and version (e.g. 1.1.0 ). - He then looks at the
shared\Microsoft.NETCore.App folder (based on the frame name) for the available versions. - Based on the available versions and the frame version from
yourapp.runtimeconfig.json it determines which version to use. Or he may decide to make a mistake and complain that the required version is not available.- π This is a complicated and sometimes confusing part.
Currently (.NET Core 1.0), the raster resolver will use the latest patch version available for the major and minor versions specified in runtimeconfig.json , but not a version lower than runtimeconfig.json . For instance. a 1.1.2 runtime will be used if the runtime configuration specifies 1.1.1 , but if only 1.1.0 , it will report an error. In addition, in earlier versions there is no roll-forward version. Thus, an application with a run-time configuration set to 1.0.0 throws an error if only 1.1.* installed.
For .NET Core 2.0, it is planned to switch to a minor version, if the corresponding minor version is not found - if the 1.0.5 are set to 1.0.5 and 1.1.2 , the application with the runtime configuration 1.0.4 will be executed at runtime 1.0.5 . If only 1.1.2 installed, then the same application will be launched on 1.1.2 . If only 2.0.0 installed, then the same application will not be able to work. See the GitHub issue for binding the .NET Core 2+ version for details and discussion of this change.
Let's see where the value in the run-time configuration came from. When you aim at the netcoreapp1.1 framework, the tool you use will determine:
- Which NuGet package (+ version) to use so that you can compile compilation links.
- What version to write to
yourapp.runtimeconfig.json
In the csproj file, the version of the structure used is determined by the property
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>
If this value is not specified, the toolkit will use the latest version that it knows about for .NET Core 1.0 and 1.1.
For .NET Core 2.0, portable applications will use the hotfix version 0 by default, and standalone applications will use the latest version that the toolkit knows about. This change occurs because tool updates (CLI "SDK" / Visual Studio) and runtime updates were released at the same time, so applications will need to install the new runtime on target systems by default. If this runtime has not been installed, an error will occur. This was bad if the hosters took several days to catch up with testing and installing updates. The version can still be forced / required if you explicitly specify <RuntimeFrameworkVersion> .
About the packages. The packages that are used in the 1. * tools are meta packages. Thus, Microsoft.NETCore.App or NETStandard.Library will be involved in many other NuGet packages. This is no longer true for .NET Core 2.0 and .NET Standard 2.0 - the packages are flat and contain everything you need. In addition, when you create a NuGet package, these packages will no longer be dependent on the package received . They are used only for compilation links, with the exception of Microsoft.NETCore.App , knowing what additional packages can be used for stand-alone applications.
Previously, a library built using NETStandard.Library version 1.6.1 would force .NET Core 1.0 applications to contain many updated DLL files that are actually part of .NET Core 1.1 . I do not know if this means that LTS policies will cover or not cover applications that fall into these DLLs. And it's hard to understand which version of .NET Core they belong to, since the versions of the packages from which they come are usually 4.0.* , 4.1.* And 4.3.* .
ASP.NET Core packages are much simpler, since they are version 1.0.* And 1.1.* So that you can see which branch they come from and you have more control over the versions used when specifying NuGet packages in the csproj file.
Recall back to the original questions:
- Given a project with a number of .Net Core dependencies. How to determine which version of the runtime should be available on the destination machine?
The real dependency is here: which version of Microsoft.NETCore.App written to the yourapp.runtimeconfig.json file. You must install the version of the same major and minor numbers and the same or higher patch numbers, the latest version of the patch will be used. When the .NET Core 2.0 converter is installed, an alternative will be to use the highest version with the same highest number, but the version of the same major and minor numbers will be preferred.
If only environments with newer major versions are installed, the application cannot be launched on the target system. (e.g. 1.0.5 application and only 2.0.0 runtime)
- Does the execution version need to match exactly, or can the runtime environment installed on the end-user computer be newer than the required version?
The run-time configuration version is a difficult minimum. To select the correct version of later time versions see above.
- Let's say I want to stick with some version of LTS at runtime. How can I determine the version of packages that I need for reference? How can I make sure that newer packages are not listed?
The version of Microsoft.NETCore.App will be automatically deduced from the target structure (for example, netcoreapp1.0 => 1.0.* , The version of the patch depending on the version of the toolkit used). To override the version, set the <RuntimeFrameworkVersion> property as described above.
If new NuGet packages are transitively applied, for example, by using Newtonsoft.Json 10.0.0 from the .NET Core 1.0 application (see the GitHub issue ), some additional DLLs may be added to the project output. These are newer versions of the DLL that are part of runtimes, but override versions from the runtime.
If you really want to make sure that you are not using any version of FTS, you will need to explicitly reference all of these packages in your csproj file so that NuGet will lower the version of packages used (and issue warnings about reduced packages).
The problem here is that there was no case where the problem was not fixed in packages 1.0 and 1.1. If this is a problem in the future, when versions 1.0 and 2.0 are supported, but will no longer be 1.1, we will need to see how this will be handled in each case. (although, of course, there is pressure / requests from the community to release updated versions 1.1, even if they are not covered by Microsoft support).
If you are using 2.0 or a higher version, these implementation packages will be separated from the dependency graph of your application and will no longer be taken into account during deployment. This happens as part of the conflict resolution logic, which knows that the new flat package contains the same DLL files as the individual packages.
- Once I know which version of execution is required on the end-user machine, how can I determine (programmatically) if this version is run-time (or a newer, backward compatible) is available?
- Scan the
shared\Microsoft.NETCore.App subfolders next to dotnet.exe and implement the same logic used by the host. - PInvoke in the native code of the last
hostfxr.dll in host\fxr next to dotnet.exe . But it is rather difficult to do.