The Visual Studio Setup and Deployment uses Prerequisites.
These Prerequisites come as Bootstrapper packages with preconfigured Product.xml and Package.xml.
Can I reuse these configuration XML or do I need to redo the configuration when I making a PackageGroup for WiX?
The SQLExpress2008R2 Bootstrapper package:
product.xml: Contains related products and calls a SQLExpressCheck.exe
package.xml: Decides on the Architecture and has default arguments for installing the SQL Server
If I cannot reuse the Product.xml and Package.xml in Burn, should I resort to the BootstrapperFile in the WixProj file?
Unfortunately, you have to create your own PackageGroups and ExePackages. While some information can be copied from the Visual Studio Bootstrapper packages, you should look for the installation documentation for the prerequisite. Sometimes the real installation instructions are hidden in the release notes or even MSDN blogs. You might have to Google for "silent" or "unattended".
It wouldn't do any good to add GenerateBootstrapper to the .wixproj file because .wixproj files are not designed to import the common microsoft targets.
I decided in my case to instead of writing Burn PackageGroups use the following setup in the wixproj.
I have 7 Bootstrapper Packages with complex product.xml and package.xml and it would have made no sense to recreate Burn Package Groups.
<ItemGroup>
<BootstrapperFile Include=".NETFramework,Version=v4.0">
<ProductName>Microsoft .NET Framework 4 (x86 und x64)</ProductName>
</BootstrapperFile>
</ItemGroup>
<PropertyGroup>
<WindowsSDKBootstrapperPath>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\GenericBootstrapper\4.0#Path)</WindowsSDKBootstrapperPath>
</PropertyGroup>
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
<GenerateBootstrapper ApplicationFile="$(TargetFileName)" ApplicationName="Rodenstock Consulting" ApplicationRequiresElevation="True" BootstrapperItems="#(BootstrapperFile)" ComponentsLocation="Relative" CopyComponents="True" OutputPath="$(OutputPath)" Path="$(WindowsSDKBootstrapperPath)" />
</Target>
Related
I have a solution with several projects targeting .NET Framework 4.7.2 and including WiX installer.
Everything works and builds fine.
In order to convert projects to .net standard/.net 6 I first convert one of the projects (extremely simple class library) to a modern Sdk format. At this moment the project file looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<RootNamespace>MyProject</RootNamespace>
<AssemblyName>MyProject</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="LegalNotice.rtf" />
</ItemGroup>
The library and all dependent projects build ok, but when building WiX installer it gives me the following error:
heat.exe(0,0): error HEAT5305: Failed to load project ...\MyProject.csproj: The default XML namespace of the project must be the MSBuild XML namespace. If the project is authored in the MSBuild 2003 format, please add xmlns="http://schemas.microsoft.com/developer/msbuild/2003" to the element. If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.
Ok, I add xmlns="http://schemas.microsoft.com/developer/msbuild/2003" to the project. All projects build ok, except WiX installer which nog gives this error:
heat.exe(0,0): error HEAT5307: Build failed.
Just to try I add ToolsVersion="15.0", the project file now looks like this:
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<RootNamespace>MyProject</RootNamespace>
<AssemblyName>MyProject</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="LegalNotice.rtf" />
</ItemGroup>
No luck. Like before, everything builds ok, except of WiX installer, which fails with the same 5307 error.
WiX version installed: 3.11.2 (the latest stable).
Any suggestions what could be the problem?
WiX v3.11 doesn't support SDK-style projects. WiX v4 will support SDK-style projects. Supporting SDK-style projects is actually, one of the biggest if not the biggest feature in WiX v4.
I have a Visual Studio 2017 solution that contains two projects:
Foo.csproj
Foo.Core.csproj
Both of these projects target multiple frameworks: net452;netstandard1.2
Foo.csproj includes a project reference to Foo.Core.csproj:
<ItemGroup>
<ProjectReference Include="..\Foo.Core\Foo.Core.csproj" />
</ItemGroup>
When I generate a NuGet package for Foo.csproj, I want the nupkg file to include both of these assemblies.
What is currently happening is that the NuGet package that gets created has Foo.dll and then a NuGet dependency on Foo.Core (which doesn't exist).
How can I generate a single NuGet package using msbuild that will include both assemblies?
For reference this is the command I am currently using (which is not working how I want it to):
msbuild /p:restore,pack Foo.csproj
This is currently not directly supported by NuGet out of the box. You can follow this GitHub issue for updates.
However, there are a few ways to create such NuGet package.
Use the "Nugetizer 3000"
This is an newly developed tool to build NuGet packages from projects and works by installing the NuGet.Build.Packaging nuget package. You can find some documentation on it on its GitHub wiki page but since it is a very new project, there isn't much documentation or community knowledge around it yet(!) (but the team developing it is very helpful, you could file GitHub issues if you get stuck).
Adding a custom target in the project (2.0.0 tooling / VS 2017 15.3+): Create an item in the csproj that will include the referenced project's output DLL
This approach is very hacky as it relies on an internal MSBuild item that the pack targets use. It works by first marking the <ProjectReference> to not be referenced from the created nuget package like this:
<ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>
Then you can add this to the project to include the generated libA.dll in the nuget package:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="IncludeP2PAssets">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
</ItemGroup>
</Target>
Note that this requires you to add all the <PackageReference> items of the referenced project to the project you generate the package from since they would be missing from the generated package since you effectively disabled the transitive reference behaviour.
Create a custom .nuspec file
At the time of writing, this is probably the most "supported" way, but also the most complex. NuGet allows you to disable the automatic generation of the resulting .nuspec file and automatic collection of files by setting the <NuspecFile> property in your project, along with a <NuspecProperties> property that allows you to pass replacement tokens for parsing the .nuspec file.
This works by modifying the project file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LibB\LibB.csproj" />
</ItemGroup>
<Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
</PropertyGroup>
</Target>
</Project>
This will automatically look for a .nuspec file with the same name as the project (somelib.csproj => somelib.nuspec) and pass some properties along to it. The properties are created in a target in order to be able to access fully resolved and defaulted properties like PackageVersion.
The .nuspec file could look like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
<file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
</files>
</package>
Note that you must add all referenced NuGet packages as a <dependency> element in the .nuspec file since these are no longer automatically generated from the <PackageReference> items in your project file. Refer to the NuSpec Reference for more details.
I have recently created an example project on GitHub demonstrating the use of a custom .nuspec file for exactly this purpose.
The second option that Martin Ullrich mentioned is the only one that works out of the box with .NET Standard that allows to "Generate NuGet package on build" as an integral part of the build.
However like he mentions it has a "hard coded" dependency on a dll with an exact name that you expect to be there (on the output folder) which might bite you in the future. I've found a better alternative which worked for me in .NET Standard without the need of any other modification on this post.
I'll quote it here for completeness.
First you edit your csproj and define the PrivateAssets tag for the reference that you'd like to include:
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
Then you add this to your csproj:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
</ItemGroup>
</Target>
That post also shows how to include the PDBs in the NuGet package option if necessary (which I omitted here).
Been struggling with the same issue and none of the suggested workarounds worked (https://github.com/NuGet/Home/issues/3891) and I couldn't change the csproj to use the new SDK coming with .netcore.
Luckily the nuget pack command comes with the -IncludeReferencedProjects option (ref: https://learn.microsoft.com/en-us/nuget/tools/cli-ref-pack) which does exactly that:
"Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package."
Regardless of the *.nuspec file (not needed here) , add -IncludeReferencedProjects to the pack command and the referenced project dlls will be included along with the nuget dll.
nuget.exe pack yourProject.csproj -IncludeReferencedProjects
I have recently discovered that you CANNOT set defaults for the Nuspec Properties you want to replace in the msbuild command line e.g. if a metadata value is set in the .csproj file of "<Version>2.0.0</Version>" and you run:
msbuild myproject.csproj -t:pack -p:Configuration=Release -p:NuspecProperties=Configuration=Release;PackageVersion=1.2.3
Your .nupgk file will have the version 2.0.0 still. Annoyingly the MS documentation is not clear on this and no error is displayed.
I am using TeamCity for a continuous integration server and am deploying my application using a ClickOnce installer. I can get the installer to function and deploy my application but I cannot figure out how to include the installer for .net 4.5 if the computer does not already have it installed or how to enable the auto-update check feature in ClickOnce deployments. I am currently using the MSBuild file below to build my installer
<Project DefaultTargets="DoPublish" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
<Version>$(BUILD_NUMBER)</Version>
<Install>true</Install>
<InstallFrom>Unc</InstallFrom>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Background</UpdateMode>
<ClickOnceBuildDirectory>$(MSBuildProjectDirectory)\MyProject\bin\$(Configuration)\app.publish</ClickOnceBuildDirectory>
<ClickOnceInstallDirectory>$(MSBuildProjectDirectory)\Publish</ClickOnceInstallDirectory>
<ClickOnceFinalLocation>$(env_PublishUrl)</ClickOnceFinalLocation>
</PropertyGroup>
<Target Name="DoPublish">
<RemoveDir Directories="$(ClickOnceInstallDirectory)" ContinueOnError="true" />
<MSBuild Projects="MyProject.sln" Targets="Clean;Build" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration)"/>
<MSBuild Projects="MyProject\MyProject.csproj" Targets="Publish" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration);InstallUrl=$(ClickOnceFinalLocation)" />
<MakeDir Directories="$(ClickOnceInstallDirectory)"/>
<Exec Command="xcopy /E $(ClickOnceBuildDirectory) $(ClickOnceInstallDirectory)" />
</Target>
</Project>
You can use a bootstrapper to handle prerequisites like checking for the .NET Framework. Check the Application Deployment Prerequisites MSDN article, especially the sections about bootstrapping with ClickOnce and MSBuild.
There are also 2 more MSDN articles that detail how to install ClickOnce prerequisites and Creating bootstrapper packages.
As for auto-updates, do you want to locate the auto-update functionality outside the application itself, i.e., in an installer vs. in the application? There are several ways to allow ClickOnce updates in your application, including auto-updates via the ClickOnce Deployment API.
A brief explanation of using ClickOnce Bootstrapper packages can be found in this existing Stackoverflow article. Though you're not using WiX here, you can also check this this WiX thread, which is useful because you see some of the steps that didn't work along the way. These examples show the use of the GenerateBootstrapper MSBuild task to create the bootstrapper for the ClickOnce installer. Note that in the examples at the above links, the "Path" in the GenerateBootstrapper task is set to a subfolder under a Windows SDK location. This can be changed to another location, as long as that location has the necessary prerequisite packages.
Below is an example in which the .NET 4.5 Framework is set as a prerequisite for the install. The parent directory structure for the .NET 4.5 prerequisite is specified by the $(MyPathToPrerequisitePackages) property.
The BootstrapperFile item in the below example specifies the .NET 4.5 Framework prerequisite package. The value ".NETFramework,Version=v4.5" comes from the product.xml file in the Bootstrapper\Packages\DotNetFX45 folder, and allows the GenerateBootstrapper task to correctly identify the .NET 4.5 prerequisite/bootstrapper package. The "ProductName" value is simply a friendly description of the package.
<PropertyGroup>
<MyPathToPrerequisitePackages>C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\Bootstrapper</MyPathToPrerequisitePackages>
</PropertyGroup>
<ItemGroup>
<BootstrapperFile Include=".NETFramework,Version=v4.5">
<ProductName>.NET Framework 4.5</ProductName>
</BootstrapperFile>
</ItemGroup>
<GenerateBootstrapper
ApplicationFile="$(MyAppAssembly).application"
ApplicationUrl="$(MyClickOnceAppUrl)"
ApplicationName="$(MyClickOnceAppName)"
BootstrapperItems="#(BootstrapperFile)"
Culture="en"
FallbackCulture="en-US"
CopyComponents="true"
Validate="false"
Path="$(MyPathToPrerequisitePackages)"
SupportUrl="$(MyAppSupportUrl)"
OutputPath="$(MyDesiredOutputPath)\" />
Just posted a response on 'https://stackoverflow.com/a/39610060/1345870':
Just struggled with this myself - I chose to commit the bootstrapper files to source control. It is possible to override the path to bootstrappers, just provide /p:GenerateBootstrapperSdkPath=.build\Bootstrapper
Then no need to modify registry - and the added benefit that the build is now self-contained.
Only "problem" is that I have to manually copy the Bootstrapper files into source control. In my case (VStudio2015), this meant copying the files from C:\Program Files (x86)\Microsoft Visual Studio 14.0\SDK\Bootstrapper
i've inherited a setup project which uses Wix 3.0
For programming reason we must switch to VS2012 and therefore to Wix 3.7, too.
While reading about Wix 3.7 i found out that 3.7 offers project type "Setup project"
and project type "Bootstrapper project".
My first question is: Have i to make a Setup project as before AND a bootstrapper project and combine it or just a bootstrapper project.
Using Wix 3.0 the bootstrapper stuff was located in the wixproj file:
<ItemGroup>
<BootstrapperFile Include="Microsoft.Net.Framework.3.5.SP1">
<ProductName>Microsoft .NET Framework 3.5 SP1</ProductName>
</BootstrapperFile>
<BootstrapperFile Include="Microsoft.Windows.Installer.3.1">
<ProductName>Windows Installer 3.1</ProductName>
</BootstrapperFile>
</ItemGroup>
<Target Name="AfterBuild">
<GenerateBootstrapper Condition=" '$(Platform)' == 'x86' " ApplicationName="$(ProductName)" BootstrapperItems="#(BootstrapperFile)" ComponentsLocation="HomeSite" CopyComponents="True" OutputPath="$(TargetDir)%(CultureGroup.OutputFolder)" Culture="%(CultureGroup.Identity)" FallbackCulture="en-us" Path="$(WindowsSDKPath)" />
<GenerateBootstrapper Condition=" '$(Platform)' == 'x64' " ApplicationName="$(ProductName) (x64)" BootstrapperItems="#(BootstrapperFile)" ComponentsLocation="HomeSite" CopyComponents="True" OutputPath="$(TargetDir)%(CultureGroup.OutputFolder)" Culture="%(CultureGroup.Identity)" FallbackCulture="en-us" Path="$(WindowsSDKPath)" />
</Target>
Is this still possible? Here i have to change from .Net 3.5SP1 to .Net 4.5
Can somebody help me?
First, you could upgrade by just using WiX Toolset 3.7 and running wixcop on your WiX files to upgrade them.
If you want to use the new WiX bootstrapper...
You need both project types. A "Setup" project creates an .msi file. A "Bootstrapper" project creates an .exe file.
Remove the Visual Studio Bootstrapper items and GenerateBootstrapper tasks from your setup project. Create corresponding ExePackage or PackageGroupRef elements in your bootstrapper's Chain. A PackageGroup roughly corresponds to a Visual Studio Bootstrapper package but the "syntax" is different. To recreate a Visual Studio Bootstrapper package consult the files under C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bootstrapper\Packages or equivalent.
For the Microsoft .NET framework, the WixNetfxExtension extension defines package groups that you can just reference.
I've managed to get builds working on my build server, but now the issue I have is that the output in the output folder contains all output from all projects, rather than just the output from the wix project(s).
Any idea how to change this?
TIA
If you are only interested in the msi as a build output then you could create a step in your team build to copy your installer files to another location, the following build target, added to your build project should help.
This overrides the target AfterDropBuild
<Target Name="AfterDropBuild">
<PropertyGroup>
<InstallerDir>$(DropLocation)\$(BuildNumber)\Installers</InstallerDir>
</PropertyGroup>
<Message Importance="low" Text="InstallerDir=$(InstallerDir)" />
<MakeDir Directories="$(InstallerDir)" Condition="!Exists('$(InstallerDir)')" />
<CreateItem Include="$(BinariesRoot)\**\*.msi">
<Output TaskParameter="Include" ItemName="InstallationFiles"/>
</CreateItem>
<Copy SourceFiles="#(InstallationFiles)"
DestinationFolder="$(InstallerDir)"/>
</Target>
I create different solution platforms { Application, Setup } and set my .NET projects to build with application and my wix to build with setup. Then I tell the build definition to build those two platforms in that order. The result is that TFS archives the .NET code in an application folder that looks like the deployed machine and the MSI in the setup folder.
Only downside is when you add new projects you have to select the platform to build in configuration manager. My developers don't seem annoyed by it though.