Porting internal email thread with @vitek-karas @SvetBonev @swaroop-sridhar @AaronRobinsonMSFT @MSLukeWest @NikolaMilosavljevic @jeffschwMSFT to this issue. Latest replies first:
From @SvetBonev
The goal is to make it really simple for customers to determine if the runtime version of .NET Core that they need is available on the machine as part of their installers.
Copy/paste from Luke’s original email:
Example Syntax: “DotNetChk.exe 3.1.0 3.1.4 Microsoft.WindowsDesktop.App X86”
Parameters:
1-2: A range of acceptable runtime versions to look for
3: The framework to look for
4: The architecture
Return values
1 if valid runtime is found
0 otherwise
The installers clarification above is important. There is a variety of installer technologies out there and they have different capabilities. Parsing text may not be possible for all of them. On the other hand, exit codes are standard.
The other consideration is that some installers run elevated. We want to make sure we don’t create conditions for elevation of privilege by calling dotnet.exe that we don’t know anything about.
A simple executable with no satellite files will be best.
Would it be possible to make the functionality available in dotnet.exe in such a way that it works without having to add extra configuration files?
Like, can we add the discovery code to dotnet.exe?
If this is not a good idea, can dotnet.exe be changed to try to load hostfxr.dll from the same folder instead of looking under the host\fxr sub-folder? That way we can ship only dotnet.exe+hostfxr.dll.
From @vitek-karas
Currently both approaches (dotnet.exe or programmatically) would need temporary files – we don’t have the APIs necessary to do this fully “in memory”.
There are potentially two ways to do this programmatically:
- Initialize everything as if it’s running an application (without actually running the app) – this has the advantage that everything will work just like if you try to run an app. The downside is that this requires not only the app.runtimeconfig.json and at least a fake app.dll, but also at least a barebone app.deps.json (I don’t know from the top of my head if this would work correctly without the .deps.json). This would handle self-contained apps as well. Basically if you have the actual app to run, you can point it to the app directly and it will tell you if it can be executed.
- Initialize the hosting as if load a component – this will do very similar things, but there are some small differences in behavior versus the app approach. One notable limitation is that this will not work for self-contained apps – you would have to detect that yourself and skip the check (which is appropriate, there’s no need to check for preinstalled dependencies if the app you’re trying to run is self-contained). This might work without any .deps.json (validation required I haven’t tried this specifically).
The high-level points of the programmatic solution would be:
- Use nethost library to search for hostfxr.dll – you can take a look at this guide (and the related sample) how that is done: https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting#create-a-host-using-nethosth-and-hostfxrh
- Either hostfxr_initialize_for_dotnet_command_line (the app-like approach from above) or hostfxr_initialize_for_runtime_config (the component approach from above).
- The result of that call will be the result of your application – if it succeeds, the given dependencies should be available on the machine.
- The above will load the appropriate hostpolicy.dll into the process if the framework resolution succeeds.
- Close the context via hostfxr_close – this should unload the hostpolicy.dll loaded above.
- Important note: with this approach only hostfxr.dll and hostpolicy.dll is loaded into the process and only hostfxr.dll will remain loaded after the attempt – and it should be possible to unload it manually. This will NOT load coreclr in any way.
Let us know if you we can help with anything.
From @MSLukeWest
Thanks Vitek. We do want to do this programmatically, and we only need .NET Core 3.1 and above. Can you elaborate on what that would look like? Would we still need to create a temporary .runtimeconfig.json file along with an app.dll?
Good note regarding needing a separate binary for x86 and x64. Given how small dotnet.exe is I don’t think it’s a problem that we’d need two of them.
From @vitek-karas
Actually you should not need hostfxr either. If it’s not on the machine then no .NET Core is available and as such you will get a nice error from dotnet.exe.
If all you want is to check if an app requiring a specific version would run, then that should do it. In that case you don’t even need to parse the output of dotnet.exe too much. Basically just create a temporary .runtimeconfig.json file with the right content another temporary app.dll and try to “run” it via dotnet.exe.
You could do this programmatically as well if you need only .NET Core 3.0 and above – in that case you would not need to spawn a separate process.
Either way doesn’t require hostfxr to come with you app – it would only use it if it’s available on the machine.
The downside of the programmatic solution is that it would have to be a separate binary for X86 and X64 (as the APIs are designed to run everything in-proc, and so can’t load the other architecture).
To answer Svet’s question: Framework/runtime discovery and resolution is done in hostfxr.dll.
From @SvetBonev
Is runtime discovery done in hostfxr.dll?
From @MSLukeWest
Thanks Swaroop and Aaron for the replies. Swaroop’s suggestion about just including dotnet.exe and hostfx.dll and parsing the output of dotnet --list-runtimes Is certainly interesting. I see that these two binaries combined are < 1mb. Swaroop – Can you confirm that if I just drop these binaries on any Windows desktop where .NET Core is supported (Win7 SP1+) they will run without any kind of framework dependencies?
From @swaroop-sridhar
I second @AaronRobinsonMSFT 's suggestion about opening a thread on github about this tool.
I’m curious why you want to build a separate tool for discovering the frameworks, rather than post-process the output of dotnet --list-runtimes.
The framework discovery is all native code, and you’d only need dotnet.exe and hostfxr.dll to get a list of all frameworks installed on the system.
We can also consider implementing the tool as a custom host that uses hostfxr but doesn’t initialize the runtime.
But I’m sure it has to live in the runtime repo.
From @AaronRobinsonMSFT
This goal sounds reasonable. I don’t know if we need a new tool or perhaps enrich an existing one. If this does go into the repo it sounds like it would be placed under https://github.com/dotnet/runtime/tree/master/src/installer/corehost. This code area is non-trivial and has incredibly high compat restrictions so heading into this just know there are going to be a lot of questions and scrutiny to add something like this to the repo.
The recommended way to get this new tool added will be through an official issue on the https://github.com/dotnet/runtime repo with the design goals, constraints, and intended test matrix. Vitek and Swaroop are the owners of this area and can review any design you have, but it needs to start on github. We are an open source repo and fully transparent about all asks and features. Getting some early feedback here is fine, but officially it needs to be on github so the community can also participate.
My experience in this area indicates this is a reasonable ask with a goal we should be able to achieve. I will say this does sounds like something ASP.NET needed at some point.
From @MSLukeWest
Swaroop / Aaron-
I’m planning on building a very simple command line tool in the dotnet runtime repo that checks whether or not a specific .NET Core runtime dependency is satisfied on a machine. You can read the attached mail for more details, but the main purpose of this is to run inside the bootstrapper of a ClickOnce/Installer project to determine if we need to install the runtime before installing an app with a .NET Core dependency. It would just perform a series of registry and folder checks, similar to what happens today when you run “dotnet --list-runtimes". A few more details:
- This would only need to be built for Windows x86 (for now at least)
- This will have to be written in native code since we can’t make any assumptions about what frameworks are installed on the machine
- I want to put it in the runtime repro since it may share some code with the dotnet cli tool, though it won’t actually ship with the runtime
- We don't need to consider the self contained app scenario here, we can assume by the time that this runs we know it's framework dependent
Example Syntax: “DotNetChk.exe 3.1.0 3.1.4 Microsoft.WindowsDesktop.App X86”
Parameters:
1-2: A range of acceptable runtime versions to look for
3: The framework to look for
4: The architecture
Return values
1 if valid runtime is found
0 otherwise
Nikola identified the two of you as potential contacts for this, I’m mainly just looking for help identifying where in the repo you’d recommend I place such a tool, as well as maybe an example project I can model mine after. Can one of you guys help point me in the right direction?
Porting internal email thread with @vitek-karas @SvetBonev @swaroop-sridhar @AaronRobinsonMSFT @MSLukeWest @NikolaMilosavljevic @jeffschwMSFT to this issue. Latest replies first:
From @SvetBonev
The goal is to make it really simple for customers to determine if the runtime version of .NET Core that they need is available on the machine as part of their installers.
Copy/paste from Luke’s original email:
Example Syntax: “DotNetChk.exe 3.1.0 3.1.4 Microsoft.WindowsDesktop.App X86”
Parameters:
1-2: A range of acceptable runtime versions to look for
3: The framework to look for
4: The architecture
Return values
1 if valid runtime is found
0 otherwise
The installers clarification above is important. There is a variety of installer technologies out there and they have different capabilities. Parsing text may not be possible for all of them. On the other hand, exit codes are standard.
The other consideration is that some installers run elevated. We want to make sure we don’t create conditions for elevation of privilege by calling dotnet.exe that we don’t know anything about.
A simple executable with no satellite files will be best.
Would it be possible to make the functionality available in dotnet.exe in such a way that it works without having to add extra configuration files?
Like, can we add the discovery code to dotnet.exe?
If this is not a good idea, can dotnet.exe be changed to try to load hostfxr.dll from the same folder instead of looking under the host\fxr sub-folder? That way we can ship only dotnet.exe+hostfxr.dll.
From @vitek-karas
Currently both approaches (dotnet.exe or programmatically) would need temporary files – we don’t have the APIs necessary to do this fully “in memory”.
There are potentially two ways to do this programmatically:
The high-level points of the programmatic solution would be:
Let us know if you we can help with anything.
From @MSLukeWest
Thanks Vitek. We do want to do this programmatically, and we only need .NET Core 3.1 and above. Can you elaborate on what that would look like? Would we still need to create a temporary .runtimeconfig.json file along with an app.dll?
Good note regarding needing a separate binary for x86 and x64. Given how small dotnet.exe is I don’t think it’s a problem that we’d need two of them.
From @vitek-karas
Actually you should not need hostfxr either. If it’s not on the machine then no .NET Core is available and as such you will get a nice error from dotnet.exe.
If all you want is to check if an app requiring a specific version would run, then that should do it. In that case you don’t even need to parse the output of dotnet.exe too much. Basically just create a temporary .runtimeconfig.json file with the right content another temporary app.dll and try to “run” it via dotnet.exe.
You could do this programmatically as well if you need only .NET Core 3.0 and above – in that case you would not need to spawn a separate process.
Either way doesn’t require hostfxr to come with you app – it would only use it if it’s available on the machine.
The downside of the programmatic solution is that it would have to be a separate binary for X86 and X64 (as the APIs are designed to run everything in-proc, and so can’t load the other architecture).
To answer Svet’s question: Framework/runtime discovery and resolution is done in hostfxr.dll.
From @SvetBonev
Is runtime discovery done in hostfxr.dll?
From @MSLukeWest
Thanks Swaroop and Aaron for the replies. Swaroop’s suggestion about just including dotnet.exe and hostfx.dll and parsing the output of dotnet --list-runtimes Is certainly interesting. I see that these two binaries combined are < 1mb. Swaroop – Can you confirm that if I just drop these binaries on any Windows desktop where .NET Core is supported (Win7 SP1+) they will run without any kind of framework dependencies?
From @swaroop-sridhar
I second @AaronRobinsonMSFT 's suggestion about opening a thread on github about this tool.
I’m curious why you want to build a separate tool for discovering the frameworks, rather than post-process the output of dotnet --list-runtimes.
The framework discovery is all native code, and you’d only need dotnet.exe and hostfxr.dll to get a list of all frameworks installed on the system.
We can also consider implementing the tool as a custom host that uses hostfxr but doesn’t initialize the runtime.
But I’m sure it has to live in the runtime repo.
From @AaronRobinsonMSFT
This goal sounds reasonable. I don’t know if we need a new tool or perhaps enrich an existing one. If this does go into the repo it sounds like it would be placed under https://github.com/dotnet/runtime/tree/master/src/installer/corehost. This code area is non-trivial and has incredibly high compat restrictions so heading into this just know there are going to be a lot of questions and scrutiny to add something like this to the repo.
The recommended way to get this new tool added will be through an official issue on the https://github.com/dotnet/runtime repo with the design goals, constraints, and intended test matrix. Vitek and Swaroop are the owners of this area and can review any design you have, but it needs to start on github. We are an open source repo and fully transparent about all asks and features. Getting some early feedback here is fine, but officially it needs to be on github so the community can also participate.
My experience in this area indicates this is a reasonable ask with a goal we should be able to achieve. I will say this does sounds like something ASP.NET needed at some point.
From @MSLukeWest
Swaroop / Aaron-
I’m planning on building a very simple command line tool in the dotnet runtime repo that checks whether or not a specific .NET Core runtime dependency is satisfied on a machine. You can read the attached mail for more details, but the main purpose of this is to run inside the bootstrapper of a ClickOnce/Installer project to determine if we need to install the runtime before installing an app with a .NET Core dependency. It would just perform a series of registry and folder checks, similar to what happens today when you run “dotnet --list-runtimes". A few more details:
Example Syntax: “DotNetChk.exe 3.1.0 3.1.4 Microsoft.WindowsDesktop.App X86”
Parameters:
1-2: A range of acceptable runtime versions to look for
3: The framework to look for
4: The architecture
Return values
1 if valid runtime is found
0 otherwise
Nikola identified the two of you as potential contacts for this, I’m mainly just looking for help identifying where in the repo you’d recommend I place such a tool, as well as maybe an example project I can model mine after. Can one of you guys help point me in the right direction?