Build Agent Considerations
Many teams build their software with a continuous integration and delivery (CI/CD) pipeline or some other kind of automated build system. Various solutions exist both as cloud services and as on-premises products. Examples include Jenkins, TeamCity, and Azure Pipelines (available both in the cloud-hosted Azure DevOps Services and the on-premises Azure DevOps Server, formally known as Microsoft Team Foundation Server or TFS).
Such systems use independent machines to carry out build steps. These machines are usually called "build agents", but some systems may refer to them as "nodes" or "executors"; this documentation will use the former term. Build agents are often virtual machines and are sometimes organized into dedicated "build farms".
Dotfuscator is designed to work on build agents, though there are some aspects of setting up, activating, and using Dotfuscator that should be considered.
How to Set Up Dotfuscator
The way your build agents are provisioned will determine the best way to set up Dotfuscator on those agents.
If you have already provisioned long-running build agents, reused across build jobs, it may be easiest to install Dotfuscator with the Windows Installer (.msi
) on each build agent.
This will allow the installations of Dotfuscator on your build agents to match the installations on your development machines, simplifying configuration.
For details, see Provisioning Dotfuscator with the Windows Installer.
If your build agents are dynamically provisioned as part of the build process, as is common with cloud-hosted build services, then using the Windows Installer on the agent may not be possible or convenient. As an example, when using Azure Pipelines with Microsoft-hosted agents, your project will be built on virtual machines which Microsoft allocates to you in a "fresh" state. In situations like this, you cannot install Dotfuscator normally and should instead use Dotfuscator's privately-distributed NuGet Package to automate installation on build agents. For details, see Provisioning Dotfuscator with the NuGet Package.
Provisioning Dotfuscator with the Windows Installer
To install Dotfuscator on a build agent for which you have administrator access, follow the normal Installation Instructions.
Depending on how you use Dotfuscator, you may need to update your projects and build scripts:
If you are using Dotfuscator via its MSBuild components, such as when following the Protect Your App instructions, then you will not need to make any modifications. This is because Dotfuscator always installs its MSBuild components in a subdirectory of the MSBuild extensions directory, and project files reference the extensions directory with a well-known MSBuild property,
$(MSBuildExtensionsPath)
.If you are using Dotfuscator's command line interface, make sure your project files and/or build scripts refer to it using the
DOTFUSCATOR_HOME
environment variable. This variable points to the directory containingdotfuscator.exe
.
After making these changes, you can build your protected app on development machines and on build agents.
Provisioning Dotfuscator with the NuGet Package
PreEmptive Solutions offers a NuGet package to Dotfuscator Professional customers. While you may be familiar with using NuGet to add third-party libraries from nuget.org to your projects, the Dotfuscator NuGet package works quite differently:
The package does not expose libraries for general programming use. Instead, the package contains Dotfuscator's various components which can be used as independent tools during a build.
You do not add a reference to the Dotfuscator NuGet package in your project. Instead, you explicitly install the package as part of your build. Your project and build scripts can then be edited to use this local installation of Dotfuscator.
The package is not available on the public nuget.org feed. Instead, the package is distributed privately from PreEmptive Solutions, and must be hosted on a private feed within your organization.
The Dotfuscator NuGet Package is offered as an alternative to the traditional Windows Installer and is designed for use with dynamically provisioned build agents. You can have your automated build system install the package as part of a build job. This makes Dotfuscator available even on machines where you cannot run the Windows Installer, such as virtual machines which are provisioned as part of the build process.
The following subsections explain how to host, install, and use the NuGet package.
Obtaining the NuGet Package
To obtain the Dotfuscator NuGet package:
Go to the Dotfuscator Downloads page and download Dotfuscator Professional. If you are not already logged in to the PreEmptive Solutions Website, you will be required to do so.
Find the version you want to download and select the Dotfuscator NuGet Package. Your browser will download the
.nupkg
file.
Hosting the NuGet Package on a Private Feed
You will need to host the Dotfuscator NuGet package in a place your build agents can access, but which is only accessible to members of your organization. To do so, you can create your own NuGet feed. Some examples include:
Uploading the package to a private, dedicated artifact repository that supports NuGet, like the cloud-hosted Azure Artifacts or the on-premises version of Artifactory. To host the package, please consult your artifact repository's user documentation. If you are using a cloud-hosted repository, you must ensure the package is not visible outside of your organization.
Placing the package in a directory on a network share (like
\\my_server\nuget
) that can be accessed by your build agents. This directory will act as a local NuGet feed.Adding the package to your source code tree, in a directory that will also act as a local NuGet feed.
This is not to be confused with the
packages
directory, which is generated by the NuGet client to hold extracted NuGet packages after they are restored. In contrast, a directory acting as a local feed only contains.nupkg
files..nupkg
files may be excluded from your source control system by default (for instance, in Git's.gitignore
). You will need to override such exclusions to add the Dotfuscator NuGet package to your source tree (in Git's case, with a--force
flag for thegit add
command).
This NuGet package is only for use inside an organization which has the right to use Dotfuscator Professional.
Installing the NuGet Package
You can use the nuget install
command to install Dotfuscator to a local directory on a build agent.
By running this command in a custom build step, later build steps can then use the various components of Dotfuscator.
Here's an example command:
nuget install -OutputDirectory "<install dir>" -ExcludeVersion PreEmptive.Protection.Dotfuscator.Pro -Source "<source url>"
where:
<install dir>
is the directory where you want to install Dotfuscator. This should be a well-known location that later build steps will use, such as a path relative to your project's root directory.<source url>
is the NuGet endpoint URL for the private feed you configured previously. For dedicated artifact repositories, use the endpoint URL exposed by the repository, such as the following (fictional) Azure Artifacts endpoint:https://pkgs.dev.azure.com/YourOrgName/_packaging/YourFeedName/nuget/v3/index.json
For local filesystem feeds, use the directory path, such as:
\\my_server\nuget
PreEmptive.Protection.Dotfuscator.Pro.Eval
instead.
We recommend you install the Dotfuscator NuGet package explicitly as described above, rather than adding the package as a reference in your project and having it be restored implicitly or with nuget restore
.
Using nuget install
allows later build steps to reference Dotfuscator's components at a well-known location, rather than one that could vary based on how the project's dependencies are restored and what version of Dotfuscator was installed.
This also prevents errors when using MSBuild components, such when following the Protect Your App instructions.
Activating Dotfuscator on Build Agents
In order for Dotfuscator to run on a build agent, you must activate Dotfuscator by providing a license key.
When using the NuGet package, we recommend setting the DOTFUSCATOR_LICENSE
environment variable to your license key as part of your automated build process.
Many build services allow you to configure environment variables which will be set for the lifetime of a build.
In others, you can set and clear the environment variable as custom build steps before and after the build, respectively.
Alternatively, you can provide the license key as an argument when using Dotfuscator.
For instance, if using the Protect Your App instructions, when calling MSBuild to build your solution you can provide the license key by setting the DotfuscatorLicense
MSBuild property:
msbuild YourSolution.sln /p:DotfuscatorLicense=<license key> <other MSBuild arguments>
In either case, please take measures to secure your license key. Some build systems offer a credential store to hold passwords and other sensitive information; you can use this to store your license key. For instance, Azure Pipelines provides the ability to declare secret variables, which are not stored in your source code and are masked from the build log. Dotfuscator itself masks all but the last four digits of the license key in its textual build output.
Licensing Server Maintenance
If the activation server is unavailable due to planned maintenance, Dotfuscator will retry the connection multiple times to avoid outright build failure. Dotfuscator will retry the connection every 30 seconds, for up to 30 minutes, by default.
The delay between connection attempts and the timeout value are configurable using the DOTFUSCATOR_MAINTENANCE_RETRY_DELAY
and DOTFUSCATOR_MAINTENANCE_RETRY_TIMEOUT
environment variables, respectively.
The DOTFUSCATOR_MAINTENANCE_RETRY_DELAY
variable sets the delay (in seconds) between connection attempts.
The DOTFUSCATOR_MAINTENANCE_RETRY_TIMEOUT
variable sets the duration of the retry period before connection failure (in minutes).
Both values must be provided as whole, positive integers.
Using the NuGet Package
After the NuGet package is installed, Dotfuscator's components will be located in <install dir>\PreEmptive.Protection.Dotfuscator.Pro\tools
.
This directory is divided into further subdirectories as follows:
programdir
contains components normally in Dotfuscator's install location, such as the command line interface.msbuilddir
contains the MSBuild components normally in Dotfuscator's MSBuild extensions path.
You will need to update your build to use the components in these directories instead of the normal directories where the Windows Installer would place the components.
PreEmptive.Protection.Dotfuscator.Pro.Eval
instead of PreEmptive.Protection.Dotfuscator.Pro
.
If you are using the main instructions on Protect Your App, your modified project file will, by default, try to import Dotfuscator's MSBuild targets from the location where the Windows Installer normally places them.
You will need to override this location by setting the DotfuscatorMSBuildDir
property when calling MSBuild for your project on a build agent:
msbuild YourSolution.sln /p:DotfuscatorMSBuildDir="<install dir>\PreEmptive.Protection.Dotfuscator.Pro\tools\msbuilddir" <other MSBuild arguments>
For Alternative Approaches, you call Dotfuscator as part of a custom build step after compiling your project.
You will need to update these build steps to use the components installed via NuGet as follows, where <install dir>
is the directory used for the nuget install
command's -OutputDirectory
argument:
The assembly containing the
Dotfuscate
MSBuild task is located at:<install dir>\PreEmptive.Protection.Dotfuscator.Pro\tools\msbuilddir\PreEmptive.Dotfuscator.Tasks.dll
The command line interface is located at:
<install dir>\PreEmptive.Protection.Dotfuscator.Pro\tools\programdir\dotfuscator.exe
If you are using the Dotfuscator Azure Pipelines Extension, set the Location of Dotfuscator application field (or, in the YAML syntax, the
dotfuscatorHome
input value) to:<install dir>\PreEmptive.Protection.Dotfuscator.Pro\tools\programdir
Note: This path must be an absolute path. To get the absolute path of the default working directory in Azure Pipelines, use the property$(System.DefaultWorkingDirectory)
.
Working with Developer Environments
Once you've updated your projects and build scripts to install the NuGet package and use its contents, your build agents will be ready to build your app and apply Dotfuscator's protection.
However, if developer machines also use these projects and scripts, you may need to make additional changes. This is because developer machines will still install Dotfuscator with the Windows Installer. While most of the same components are deployed with both the NuGet package and the Windows Installer, factors such as installation location and system-wide environment variables can cause differences between environments.
For example, if your Visual Studio project file uses the Dotfuscate
task, the project must contain a <UsingTask>
directive specifying the on-disk location of the assembly holding the task.
This location varies based on how you installed Dotfuscator.
The project must accommodate both possibilities to avoid errors when it is opened in Visual Studio.
DotfuscatorMSBuildDir
property described in the previous section.
You do not have to make any changes to have Dotfuscator work on developer environments in this case.
Here are some possible strategies for having your shared projects and build scripts work with Dotfuscator in both developer and build environments:
Pass the Dotfuscator paths into the projects and build scripts. Typically you should default to the locations of components laid down by the Windows Installer, and have your automated build system override the paths to point to the NuGet installation. This allows developers to continue working with the project as they normally do, while having build agents use the NuGet package.
As an example of this strategy, consider the Protect Your App instructions, which import Dotfuscator's MSBuild targets. Here's an excerpt of the relevant lines the instructions have you add to the Visual Studio project file:
<PropertyGroup> <DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4</DotfuscatorMSBuildDir> </PropertyGroup> <Import Project="$(DotfuscatorMSBuildDir)\PreEmptive.Dotfuscator.Common.targets" />
First, an MSBuild property,
DotfuscatorMSBuildDir
, if not already set, is set to the Windows Installer location of Dotfuscator's MSBuild components. Then, this property is used in the<Import>
tag to point to the directory holding the targets file.If the property is set when MSBuild is called, that directory's path will be used instead of the Windows Installer location. This is why you have to specify this property explicitly when building the project with the Dotfuscator NuGet package; otherwise, it will default to the Windows Installer location and fail to build because the targets are not at that location on the build agents.
You can modify this strategy by having both sets of paths be hard-coded in your projects and build scripts, but choosing which set to use based on a flag set by automated builds.
Use the NuGet package instead of the Windows Installer on developer machines. This will make the developer environments consistent with the build agents, thus allowing your projects and build scripts to refer to Dotfuscator at one consistent location.
However, there are a number of consequences of this strategy:
The
nuget install
command must be run with the same arguments as it is during the build, to ensure the package is installed to the same location. We recommend making a batch file or script containing the specific command your build relies on, so developers can easily run the command without having to type in the arguments.Visual Studio cannot open projects that reference MSBuild components, such as those modified with the recommended Protect Your App instructions, until the
nuget install
command has run.The developer must run
nuget install
before Dotfuscator can successfully be run as part of a build.The developer must activate Dotfuscator, usually by setting an environment variable, before it can run successfully as part of a build.
There will not be a Start Menu shortcut to the Config Editor. Instead, the developer must run
programdir\dotfuscatorUI.exe
in the NuGet package's install location.The
DOTFUSCATOR_HOME
environment variable will not automatically be set, and Dotfuscator's executables will not be on the PATH. Instead, the components of Dotfuscator must be referenced explicitly based on the NuGet package's install location.
Use the NuGet package in addition to the Windows Installer on developer machines. This is similar to the previous strategy, with the difference being that the developer also installs Dotfuscator with the Windows Installer. The Dotfuscator installation will exist at the same time as the installed NuGet package.
In this strategy, the developer will still need to run
nuget install
in order for projects and build scripts to work, as they refer to the Dotfuscator components in the NuGet package installation. As a result, this strategy still has consequences 1, 2, and 3 from the previous strategy.However, using the Windows Installer will add the Start Menu shortcuts and set the
DOTFUSCATOR_HOME
environment variable. The developer can activate Dotfuscator during the installation or when running the Config Editor from the Start Menu. This mitigates consequences 4, 5, and 6.
Once you have applied a strategy, apply it consistently across your team and test that Dotfuscator runs on both developer environments and as part of automated builds.