Use this article to configure Dotfuscator in your project or build process.
For many .NET and Xamarin projects, the recommended approach is to integrate Dotfuscator with MSBuild. In this workflow, Dotfuscator runs automatically when you build the project in a Dotfuscator-enabled configuration, such as Release.
When to Use MSBuild
Use MSBuild if you:
- Build applications using Visual Studio.
- Build applications using the .NET SDK.
- Want protection to run automatically during builds.
- Want to ship obfuscated executables and mobile application distributables.
- Use build servers or CI/CD pipelines.
- Want to apply the same protection settings to every build.
Use Dotfuscator MSBuild Targets
The MSBuild targets approach integrates Dotfuscator directly into the project file. After integration, Dotfuscator runs as part of the build.
Use the section that matches your project type:
- .NET 5+, .NET Core, .NET Standard, or MAUI
- .NET Framework
- Xamarin
.NET 5+, .NET Core, .NET Standard, and MAUI Projects
Modern .NET projects usually use SDK-style project files. To protect an SDK-style project, make sure the Dotfuscator targets file is imported last. The current article explains that this requires replacing the Sdk attribute with explicit SDK imports.
- Remove the
Sdkattribute from the root<Project>tag. - Add the SDK property import near the top of the file.
- Add the SDK targets import near the bottom of the file.
- Add the Dotfuscator properties and targets import after the SDK targets import.
Example:
<!-- ORIGINALLY WAS: <Project Sdk="Microsoft.NET.Sdk"> OR similar -->
<Project>
<!-- Import SDK properties before existing tags. -->
<!-- TODO: Update the Sdk value to match the value originally used in the Project tag. -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- ...existing tags... -->
<!-- Import SDK targets after existing tags but before Dotfuscator targets. -->
<!-- TODO: Update the Sdk value to match the value originally used in the Project tag. -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<!-- Import environment-specific build properties for Dotfuscator, if they exist. -->
<Import Project="$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props"
Condition="Exists('$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props')"/>
<!-- Set build properties for Dotfuscator. -->
<PropertyGroup>
<!-- Specify the location of the MSBuild targets, if not already provided. -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildProgramFiles32)/MSBuild/PreEmptive/Dotfuscator/7</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) if it doesn't exist. -->
<!-- TODO: Set this to false after the file is generated by the first local build. -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release builds. -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets. Must be done last. -->
<Import Project="$(DotfuscatorMSBuildDir)/PreEmptive.Dotfuscator.Common.targets" />
</Project>.NET Framework Projects
To protect a .NET Framework project, copy the new XML elements and paste them immediately before the closing </Project> tag in the project file.
<!-- Import environment-specific build properties for Dotfuscator, if they exist. -->
<Import Project="$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props"
Condition="Exists('$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props')"/>
<!-- Set build properties for Dotfuscator. -->
<PropertyGroup>
<!-- Specify the location of the MSBuild targets, if not already provided. -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildProgramFiles32)/MSBuild/PreEmptive/Dotfuscator/7</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) if it doesn't exist. -->
<!-- TODO: Set this to false after the file is generated by the first local build. -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release builds. -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets. Must be done last. -->
<Import Project="$(DotfuscatorMSBuildDir)/PreEmptive.Dotfuscator.Common.targets" />Xamarin Projects
For Xamarin projects, integrate Dotfuscator into each output project that you want to protect.
For example, if your app targets both Android and iOS, integrate Dotfuscator into each corresponding output project. The current article also recommends starting with Android.
<!-- Import environment-specific build properties for Dotfuscator, if they exist. -->
<Import Project="$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props"
Condition="Exists('$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props')"/>
<!-- Set build properties for Dotfuscator. -->
<PropertyGroup>
<!-- Specify the location of the MSBuild targets, if not already provided. -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildProgramFiles32)/MSBuild/PreEmptive/Dotfuscator/7</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) if it doesn't exist. -->
<!-- TODO: Set this to false after the file is generated by the first local build. -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release builds. -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
<!-- Enable Dotfuscator for Ad-Hoc builds. Only needed for iOS. -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Ad-Hoc'">true</DotfuscatorEnabled>
<!-- Enable Dotfuscator for AppStore builds. Only needed for iOS. -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'AppStore'">true</DotfuscatorEnabled>
<!-- Only needed when using Tamper Checks for Android. -->
<!-- TODO: If using Tamper Checks for Android, set this to the SHA-1 fingerprint of the certificate used to sign the app. -->
<!-- If you use key rotation and your application requires Android Pie or later, use the last alias in the rotation. Otherwise, provide the first alias in the rotation. -->
<DotfuscatorAndroidSigningCertFingerprint></DotfuscatorAndroidSigningCertFingerprint>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets. Must be done last. -->
<Import Project="$(DotfuscatorMSBuildDir)/PreEmptive.Dotfuscator.Common.targets" />Understand Dotfuscator MSBuild Properties
The Dotfuscator MSBuild integration uses several properties.
| Property | Description |
DotfuscatorMSBuildDir | Specifies the location of the Dotfuscator MSBuild targets. |
DotfuscatorGenerateConfigFileIfMissing | Controls whether Dotfuscator generates DotfuscatorConfig.xml when the file does not exist. |
DotfuscatorEnabled | Controls whether Dotfuscator runs for a specific build configuration, such as Release. |
DotfuscatorAndroidSigningCertFingerprint | Specifies the Android signing certificate fingerprint when you use Tamper Checks for Android. |
Disable Config File Generation After the First Build
During the first build, Dotfuscator can generate DotfuscatorConfig.xml with default protection settings. This is useful during initial setup.
After the file exists and is checked into version control, set DotfuscatorGenerateConfigFileIfMissing to false.
Replace:
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) if it doesn't exist. -->
<!-- TODO: Set this to false after the file is generated by the first local build. -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>With:
<!-- Error if the Dotfuscator config file (DotfuscatorConfig.xml) is missing. -->
<DotfuscatorGenerateConfigFileIfMissing>false</DotfuscatorGenerateConfigFileIfMissing>This helps prevent the build from silently creating a new default config file when the expected config file is missing.
Alternative Approaches
The MSBuild targets approach works well for many projects, but it may not fit every build process.
Use an alternative approach if any of the following are true:
- Your project uses a custom MSBuild structure that does not use common .NET Framework targets, such as
Microsoft.CSharp.targets, or a .NET SDK, such asMicrosoft.NET.Sdk. - You need to use Dotfuscator’s Linking feature.
- You need Dotfuscator to run after the MSBuild packaging steps.
- Your project uses a build system that is not based on MSBuild.
- You do not have access to the project file and only have the compiled
.exeor.dllfiles.
The original article lists these same cases as scenarios where the recommended MSBuild targets approach may not be suitable.
General Alternative Workflow
When you use an alternative approach, run Dotfuscator after the normal compilation step.
Use this general workflow:
- Create a Dotfuscator config file.
- Configure the config file in the Config Editor or through the CLI with:
- the assemblies Dotfuscator protects,
- the output location for the protected assemblies,
- the protection settings you want to apply.
- If you use an automated build system, install Dotfuscator on your build agents.
- Run Dotfuscator after your build system compiles the app.
- Pass the path to the Dotfuscator config file when you run Dotfuscator.
- Archive the generated report files after each build or release build.
Create a Config File
You can create a Dotfuscator config file in different ways:
- On Windows, use the graphical Config Editor to create and test the configuration locally.
- On all platforms, use the Dotfuscator command line interface to create and test the configuration.
- Use a text editor to create or update the config file manually.
Run Dotfuscator with an MSBuild Task
Use the Dotfuscate MSBuild task if you are familiar with MSBuild and want to call Dotfuscator from a custom MSBuild target.
For example, you can run Dotfuscator after the Build target:
<!-- Import environment-specific properties, which may include DotfuscatorMSBuildDir. -->
<Import Project="$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props"
Condition="Exists('$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))/.dotfuscator.user.props')" />
<!-- Set a default value for the DotfuscatorMSBuildDir property. -->
<PropertyGroup>
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildProgramFiles32)/MSBuild/PreEmptive/Dotfuscator/7</DotfuscatorMSBuildDir>
</PropertyGroup>
<!-- Reference the Dotfuscate task using the DotfuscatorMSBuildDir property. -->
<UsingTask TaskName="PreEmptive.Tasks.Dotfuscate"
AssemblyFile="$(DotfuscatorMSBuildDir)/PreEmptive.Dotfuscator.Tasks.dll" />
<!-- Run Dotfuscator after the Build target. -->
<Target Name="MyTarget" AfterTargets="Build">
<Dotfuscate ConfigPath="path/to/your/DotfuscatorConfig.xml"
License="$(DotfuscatorLicense)" />
</Target>Archive Report Files
Dotfuscator produces report files when it protects your app. Preserve these files for every release build, and preferably for every automated build.
If your team uses CI/CD, configure the pipeline to archive the generated report files after Dotfuscator runs. If you build manually, add this step to your release checklist.
Store the report files in a secure, versioned location.
Next Steps
After you configure Dotfuscator build integration:
- Build the project in a Dotfuscator-enabled configuration.
- Confirm that
DotfuscatorConfig.xmlexists and is checked into version control. - Confirm that Dotfuscator creates protected
.exeor.dllfiles. - Archive the generated report files.
- Review additional protection options.
- Review the release checklist before distributing protected software.