How to check whether the .NET 6 runtime is installed - .net-core

As part of installation of a WPF application using .NET 6 and a WiX installer, I would like to check whether the .NET 6 runtime is installed.
WiX provides pre-defined properties to check this for .NET framework but nothing for .NET Core and beyond so I am attempting to check for the presence of a registry key.
There is a registry key that can be checked under: HKEY_LOCAL_MACHINE\SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedhost\Version
However, if I uninstall the runtime the registry key does not get removed, is there any other reliable way to check whether the runtime is installed, as well as which version is installed?

WiX 3 currently doesn't handle this natively. It is being worked on for WiX v4 (GitHub issue). Reading the issue led me to these tools as a current workaround.
https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x86
https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x64
You can use the files inside of these packages to check for a runtime. Either by running NetCoreCheck.exe directly or using the custom action DLL provided.
NetCoreCheck.exe -h to see help. But you'll want something like this:
netcorecheck --runtimename Microsoft.NetCore.App --runtimeversion 6.0.0
I don't know how to use the custom action dll but I do see it has two DLL exports.
ordinal hint RVA name
1 0 00001500 CheckNETRuntime
2 1 00002260 get_hostfxr_path

You may use the Custom Action DLL mentioned in Hank's answer if you want to integrate this in your WiX project.
You can use the NuGet package to obtain the dll.
Unfortunately there seems to be no documentation in existence for this DLL, so I used the source code to figure out how this works.
First you need to define a few properties that are used as input parameters for the .NET runtime check, and for the result of the check.
<Property Id="CheckNETRuntime_Framework" Value="Microsoft.AspNetCore.App" />
<Property Id="CheckNETRuntime_Version" Value="6.0.0" />
<Property Id="CheckNETRuntime_Result" />
CheckNETRuntime_Framework is the framework to search for. There are currently 3 options:
Microsoft.NETCore.App
Microsoft.AspNetCore.App
Microsoft.WindowsDesktop.App
CheckNETRuntime_Version is the version of .NET to look for.
The result will be stored in CheckNETRuntime_Result. A value of 0 indicates the runtime was found, any other value indicates it was not found.
To run the custom action, do this:
<Binary Id="CustomActions" SourceFile="NetCoreCheckCA.dll" /> <!-- This should be the path to the dll -->
<CustomAction Id="CheckRuntime" Return="ignore" BinaryKey="CustomActions" DllEntry="CheckNETRuntime" />
<InstallExecuteSequence>
<Custom Action="CheckRuntime" Before="LaunchConditions" />
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="CheckRuntime" Before="LaunchConditions" />
</InstallUISequence>
Note: you need to add Return="ignore" if you do not want the installer to fail when the runtime was not found (as the return value if not 0, which indicates a failure).
The CheckNETRuntime_Result property can be used elsewhere in your setup, for example you could use it in a condition:
<Condition Message=".NET 6 runtime is not installed">
<![CDATA[CheckNETRuntime_Result=0]]>
</Condition>

Related

How can we avoid that every package in our .NET Core 3.1 project, is checked at every NuGet source during Azure DevOps pipeline?

In our .NET Core 3.1 project (REST API), we've multiple NuGet packages. General packages comes from the nuget.org source, some custom made packages are retrieved from a private source.
In Azure DevOps, we've a build pipeline with a task to restore the NuGet packages. Here we saw that every packages was checked with every source. A general package such as Swashbuckle.AspNetCore.SwaggerGen was also searched on our private source.
Due to the amount of requests from DevOps, the first attempt of the pipeline was interpreted as a DOS attack on our system. When the failed run was started again, the task succeeds without any error.
- task: DotNetCoreCLI#2
displayName: dotnet restore
inputs:
command: 'restore'
projects: '**/*.sln'
feedsToUse: 'config'
nugetConfigPath: 'src/NuGet.config'
In the tasks detail, we see the below message returning for every package.
GET private_source/nuget/FindPackagesById()?id='xunit.analyzers'&semVerLevel=2.0.0
Retrying 'FindPackagesByIdAsyncCore' for source 'private_source/nuget/FindPackagesById()?id='Microsoft.AspNetCore.Mvc.Razor'&semVerLevel=2.0.0'.
An error occurred while sending the request.
The response ended prematurely.
How can we avoid that every package in our solution, is checked at every NuGet source? Or what can we change to get a successfull build the first time?
NuGet recently introduced the feature, called Package Source Mapping: https://devblogs.microsoft.com/nuget/introducing-package-source-mapping/
Here's the nuget.config snippet from the blog post:
<!-- Define my package sources, nuget.org and contoso.com. -->
<!-- `clear` ensures no additional sources are inherited from another config file. -->
<packageSources>
<clear />
<!-- `key` can be any identifier for your source. -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="contoso.com" value="https://contoso.com/packages/" />
</packageSources>
<!-- Define mappings by adding package ID patterns beneath the target source. -->
<!-- Contoso.* packages will be restored from contoso.com, everything else from nuget.org. -->
<packageSourceMapping>
<!-- key value for <packageSource> should match key values from <packageSources> element -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="contoso.com">
<package pattern="Contoso.*" />
</packageSource>
</packageSourceMapping>
Regarding the error message:
An error occurred while sending the request. The response ended prematurely.
This suggests there's something wrong with the server or networking. A good nuget server should return HTTP 404 for packages that doesn't exist on it. Implementing package source mapping might not solve your restore problem.
I suggest creating an Azure Devops Artifacts feed having upstream source both from nuget.org and your private feed. There is no other way you can use multiple sources to do partial restore.
How can we avoid that every package in our .NET Core 3.1 project, is checked at every NuGet source during Azure DevOps pipeline?
I am afraid there is no such out of box way to resolve this restriction.
That's because no matter how we set the resource, when we restore the package for the first time, nuget.exe will iterate over each resource for every package. This problem will be alleviated when we run the pipeline again, because it is from nuget.org The packages will be cached in our private feed. When we restore again, it will be retrieved from the private feed first:
Check my previous thread for some more details.
Besides, If you want to avoid this problem the first time, you can try not to restore the entire .sln file, you can choose package.configs for the specify reject:

WiX Bundle gets "Failed to verify hash of payload" when trying to install .net core hosting bundle from web

I have a burn/bootstrapper WiX bundle with:
<?define DotNetVersion = "2.1.11"?>
<!-- The Min and Next .Net version that our installed version must be between -->
<Variable Name='MinDotNetVersion' Type='string' Value='2.1.0' bal:Overridable='no'/>
<Variable Name='NextDotNetVersion' Type='string' Value='2.2.0' bal:Overridable='no'/>
<?define HostingBundleUrl = "https://www.microsoft.com/net/download/thank-you/dotnet-runtime-$(var.DotNetVersion)-windows-hosting-bundle-installer" ?>
<util:RegistrySearch Id="DotNetHostingBundle86"
Root="HKLM"
Key="SOFTWARE\dotnet\Setup\InstalledVersions\$(var.Platform)\sharedhost"
Value="Version"
Variable="DotNetHostingBundleVersion" />
<!-- If running installer in a 32-bit process will change above key path to wow6432 etc, then won't find it. So, if didn't find it and version is x64, get the variable
this way: -->
<util:RegistrySearch Id="DotNetHostingBundle64"
After="DotNetHostingBundle86"
Condition="NOT DotNetHostingBundleVersion AND VersionNT64"
Root="HKLM"
Key="SOFTWARE\dotnet\Setup\InstalledVersions\$(var.Platform)\sharedhost"
Value="Version"
Variable="DotNetHostingBundleVersion"
Win64="yes"/>
<Chain>
<ExePackage Id="DotNetCoreHostingBundle"
Vital="yes"
Name=".Net Hosting Bundle Setup"
DownloadUrl="$(var.HostingBundleUrl)"
Compressed="no"
SourceFile=".\ExtResourcesCopy\dotnet-hosting-$(var.DotNetVersion)-win.exe"
InstallCondition="NOT DotNetHostingBundleVersion OR (DotNetHostingBundleVersion < MinDotNetVersion OR DotNetHostingBundleVersion >= NextDotNetVersion)"
Description="Installing .Net Hosting Bundle $(var.DotNetVersion). This includes the 32 bit and 64 bit runtimes, the Asp.net runtime packages (Microsoft.AspNetCore.App and .All), and the IIS Hosting Components."
/>
...
I've downloaded the dotnet-hosting-2.1.11-win.exe file into the ExtResourcesCopy folder, and since I set the SourceFile to this it gets its own Payload data.
I then build my .exe and run it on another computer and get the following error:
Acquiring package: DotNetCoreHostingBundle, payload: DotNetCoreHostingBundle, download from: https://www.microsoft.com/net/download/thank-you/dotnet-runtime-2.1.11-windows-hosting-bundle-installer
Error 0x80091007: Hash mismatch for path: C:\ProgramData\Package Cache\.unverified\DotNetCoreHostingBundle, expected: 1ED626AD403D6E5D99AB69DB7C281FB8E8A8D0A2, actual: F21BF2F13F89D1C9DFD2844D57728102D5714EAA
Error 0x80091007: Failed to verify hash of payload: DotNetCoreHostingBundle
Failed to verify payload: DotNetCoreHostingBundle at path: C:\ProgramData\Package Cache\.unverified\DotNetCoreHostingBundle, error: 0x80091007. Deleting file.
I then checked the SHA1 hash on the target computer by downloading the dotnet-hosting-2.1.11-win.exe file manually from Microsoft, using the exact url from the log file, and running:
certutil -hashfile dotnet-hosting-2.1.11-win.exe
This gave me the expected hash of: 1ed626ad403d6e5d99ab69db7c281fb8e8a8d0a2
So where is this "actual" hash of F21BF2F13F89D1C9DFD2844D57728102D5714EAA coming from? Is there a way of pausing the installer so I can inspect the file in the .unverified folder? And/or what can I do about this?
The URL you're using is an HTML page that uses JavaScript to download the package. Burn just sees the HTML.
You should be able to use dark.exe to decompile your bundle executable and see the hashes for all of the payloads.
Note: Those hashes are present for security purposes. They prevent bad actors from tampering with the install content.

Apache Karaf feature dependency

In feature.xml (Apache Karaf provisioning mechanism) tag feature has a dependency attribute. What does this attribute do?
For example:
<feature dependency="true">custom-feature-name</feature>
Where can I find any information on it?
After a brief googling I've only found dependency attribute on a bundle tag:
The role of the dependency attribute is to mark that a bundle is a dependency. If a dependency is already satisfied (an existing bundle already exports the same packages/version) then it doesn't get installed. This behavior happens if the declared feature resolver is installed (e.g. obr is installed).
Source:
http://karaf.922171.n3.nabble.com/features-xml-dependency-quot-true-quot-td3286359.html
But still, no information on feature tag.
It would seem that the definition of dependency for features in
<feature name="${project.name}-cxf" version="${cxfVersion}" description="Gets CXF up and running." install="auto">
<feature version="${cxfVersion}" dependency="true">cxf</feature>
</feature>
means that the feature ${project.name}-cxf does not have to start cxf, because it is declared that something else will provide it. This is indeed counterintuitive. Whoever came up with that ludicrous misnomer?
To auto install cxf, it should actually be set to false. This can be varified by looking up the name of the feature ${project.name}-cxf when dependency="true" and again set to false.
Developers of Karaf, the dependency=false should be renamed provided=true

Reducing the size of my natively deployed JavaFX application

I'm writing an application with JavaFX and am concerned about the size of the .EXE file that I'll be natively deploying. The application that I have is not so big (all together less than 5M), but the Java Runtime is making the final installed directory well over 100M which compresses into a ditributable 44M file.
I've been running tests with 64-bit Windows (Java SE 8u77). To make the final executable smaller I've removed parts of the JRE that are unnecessary as outlined here: http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html
Here's what I've found:
Complete JRE : 45.0 M
Stripped JRE : 44.0 M
Does anyone have any ideas on how to make the distributable .EXE even smaller? All of the information I've found is at least 2 or 3 years old and maybe not so relevant anymore. I'm feeling like there's more that can come out of the JRE, but it seems that that would violate the licensing.
Does anyone have any experience using any non-Oracle distributions or any other ways to make the JavaFX app smaller?
When using the javapackager, you can set to NOT include the JRE. This makes the native launcher use the local installed JRE (which might not be the best solution).
When using the javafx-maven-plugin, you just have to set a bundlerArgument:
<configuration>
<mainClass>com.zenjava.test.Main</mainClass>
<bundleArguments>
<runtime /> <!-- dont include JRE, use installed one -->
</bundleArguments>
</configuration>
When using the javafx-gradle-plugin, just set the runtime as NULL:
jfx {
verbose = true
mainClass = 'your.application.appname'
appName = 'appname'
jfxMainAppJarName = 'appname.jar'
vendor = "My Company"
bundleArguments = [
runtime: null
]
}
When using the ant-style xml-file of the javapacker itself, just set this:
<fx:bundleArgument name="runtime" value="" />
Disclaimer: I'm the maintainer of the javafx-maven-plugin and the creator of the javafx-gradle-plugin.
One of the best tools for this is Proguard.
Run your program through it before generating an executable

Imagine Bundle conflict minimum

I'd like to install liip/imagine-bundle in my symfony 2 project. But in order to make barcodes, I installed previously MopaBarcodeBundle.
MopaBarcodeBundle requires "avalanche123/imagine-bundle" which requires imagine/imagine: v0.4.1
And
LiipImagineBundle requires imagine/imagine: ~0.5,<0.7
Obviously composer detects the conflict, as he cannot unistall v0.4.1, and that version is not enough for LiipImagine.
I'd like to know how I could bypass this. Create sorts of aliases in composer and keep the two versions on my project ? I'm not a pro in version management, so I guess this is not possible.
Thank you very much for any help.
Ok, after some code inspection i figured out a way around. MopaBarcodeBundle doesn't really requires avalanche123/imagine-bundle, but it uses it in the service declaration. (To make the link with Imagine classes).
So I changed the service.xml file containing the BarcodeService declaration.
<parameter key="imagine.gd.class">Imagine\Gd\Imagine</parameter>
<service id="imagine" alias="imagine.gd" />
<service id="imagine.gd" class="%imagine.gd.class%" />
I guess thoses lines could be factorised, but i chose to keep it as it was done in avalanche123.
Also a constant from avalanche was used in 5th argument, I changed it to :
<argument>%kernel.root_dir%../web</argument>
Finally I removed avalanche, and then install a newer version of imagine/imagine

Resources