Renaming is designed to preserve application behavior while making code more difficult to understand. In most cases, Dotfuscator can safely rename identifiers without requiring additional configuration.
However, some applications contain code that depends on specific names remaining unchanged. When these scenarios are present, you may need to exclude certain code elements from renaming.
This article describes common situations that may require renaming exclusions and explains the available approaches for excluding code from renaming.
Why Renaming Exclusions Are Necessary
Renaming changes the names of identifiers such as:
- Namespaces
- Types
- Methods
- Properties
- Fields
- Events
Most applications continue to function normally after renaming. However, some application components rely on original names at runtime. If those names are changed, application functionality may be affected.
When introducing renaming into an application, thoroughly test the protected application and identify any components that require their original names to remain unchanged.
Common Scenarios Requiring Exclusions
The following scenarios commonly require renaming exclusions.
| Scenario | Why Exclusions May Be Required |
| Reflection | Applications that use reflection may access types or members by name at runtime. If a reflected type or member is renamed, the application may no longer be able to locate it. |
| Serialization | Some serialization mechanisms depend on type or member names when converting objects to and from serialized data. If these names are changed during renaming, serialization or deserialization may fail. |
| Dynamic Loading | Applications may dynamically load types, assemblies, or members using their names. If the referenced names are renamed, the application may be unable to locate the required components. |
| Framework and Library Requirements | Some frameworks, libraries, and generated code rely on naming conventions or runtime discovery mechanisms. Renaming may require exclusions to maintain compatibility. |
| External Configuration Files | Applications may store type or member names in configuration files, XML files, JSON files, databases, or other external resources. If these names are renamed, the application may no longer be able to locate the referenced code elements. |
| Interoperability Scenarios | Applications that interact with external systems, plugins, or components may depend on specific names remaining unchanged. Renaming may require exclusions to preserve compatibility. |
When introducing renaming into an application, thoroughly test the protected application and identify any code that depends on original names remaining unchanged.
Approaches to Renaming Exclusions
Dotfuscator provides several mechanisms for excluding code from renaming.
Choose the approach that best fits your application's requirements and development process.
Specific Exclusions
Specific exclusions are applied directly to individual code elements.
Use specific exclusions when only a small number of types or members must retain their original names.
- In the Config Editor, go to Rename > Exclusions.
- Select the classes and fields that should be excluded.
Specific exclusions provide precise control but may require additional maintenance as the application evolves.
BugSweeper Example
This example uses the protected BugSweeper.Android app available at Samples.
When you launch the protected BugSweeper.Android app on an Android device, the app runs. However, you notice the text that reports how many bugs are left to find (for example, "Flagged 2 out of 10 bugs.") is not updating as you play the game:
To fix the issue, you do the following:
- After enabling USB debugging on the phone, open Android device log in Visual Studio to see detailed logs about possible errors. Filter the log down to just Error and Warning for clarity.
-
Inspect the stack trace of the error to locate the source. For example, the following stack trace shows an error in a method named b() on type BugSweeper.BugSweeperPage.
Caused by: android.runtime.JavaProxyThrowable: System.Exception: Can't resolve name on Element at Xamarin.Forms.Xaml.ReferenceExtension.ProvideValue (System.IServiceProvider serviceProvider) [0x000b6] in <cdab8e5cc6744897b152dd4075cc1cb0>:0 ... at Xamarin.Forms.Xaml.Extensions.LoadFromXaml[TXaml] (TXaml view, System.Type callingType) [0x00000] in <cdab8e5cc6744897b152dd4075cc1cb0>:0 at BugSweeper.BugSweeperPage.b () [0x00000] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 at BugSweeper.BugSweeperPage..ctor () [0x00006] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 at BugSweeper.App..ctor () [0x00006] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 at BugSweeper.Droid.MainActivity.OnCreate (Android.OS.Bundle bundle) [0x0000e] in <bf5a3ea557124c988f94e73e801e2727>:0 ... -
Open the renaming map file (C:\code\BugSweeper\BugSweeper\BugSweeper.Android\DotfuscatorReports\Release\Renaming.xml) and look up the appropriate module (BugSweeper.dll), name (BugSweeper.BugSweeperPage), and method (new name of b):
<mapping> <module> <name>BugSweeper.dll</name> <type> <name>BugSweeper.BugSweeperPage</name> <methodlist> <method> <signature>void()</signature> <name>InitializeComponent</name> <newname>b</newname> </method> </methodlist> </type> </module> </mapping> - The map file indicates the original name of the b method is InitializeComponent. Set this as the initial place to start looking for the source of the error.
-
In the source code, note that the BugSweeperPage.xaml file defines this text using two labels, each with a BindingContext to the board field:
<StackLayout Orientation="Horizontal" Spacing="0" VerticalOptions="CenterAndExpand" HorizontalOptions="Center"> <Label BindingContext="{x:Reference board}" Text="{Binding FlaggedTileCount, StringFormat='Flagged {0} '}" /> <Label BindingContext="{x:Reference board}" Text="{Binding BugCount, StringFormat=' out of {0} bugs.'}" /> </StackLayout> - Decide the issue must be due to the BugCount property being renamed. You exclude this manually from the Dotfuscator Config Editor.
- Build and redeploy BugSweeper.Android. This time the app runs, and there are no problems when playing, winning, or losing the game.
- Commit the change you made to DotfuscatorConfig.xml to local version control.
Custom Exclusion Rules
Custom exclusion rules allow you to exclude groups of code elements that share common characteristics. For example, you may notice that in your application, all types with names ending in "Dungeon", and specific types of fields within those types, need to be excluded from renaming for some reason.
Rather than creating a bunch of specific exclusions, you can make one custom rule as follows in the Renaming editor:
- In the Config Editor, go to Rename > Exclude.
- Add the rule's root node by selecting the Add Type option.
- Enter
.*Dungeonin the Name field. - Check the Regular Expression (regex) option to indicate that the name should be treated as a regular expression. This way the node matches types whose names end in "Dungeon".
- Check the Exclude Type (excludetype) option to exclude matching types. If you do not select this option, the types that match are not excluded from renaming - only the members specified by their child nodes.
- Add a child node by right-clicking the root node and selecting Add Field.
- Name the child node
.*and indicate that it should be treated as a regular expression. - Restrict the rule to only cover fields which have the public access modifier (by setting
+public), and whose signature isstring[], as both are necessary in this scenario.
Once you configure a rule, you can select a node and click the Preview button. Dotfuscator highlights the entries that match your custom rule in the tree view on the left. You can see the rule on the right pane.
In this example, the Keys field in AdventureGame.Validation is not excluded, because while it matches this child node, its parent type does not match the parent node (the class name "Validation" does not end in "Dungeon").
The resulting configuration of this custom rule is stored as XML in the config file. This example produces the following config XML:
<type name=".*Dungeon" regex="true">
<field name=".*" speclist="+public" signature="string[]" regex="true" />
</type>Custom rules can reduce maintenance effort compared to managing a large number of individual exclusions.
Built-In Rules
Dotfuscator includes built-in exclusion rules for common framework and library scenarios.
Built-in rules can help preserve compatibility without requiring manual exclusion configuration.
Review the available built-in rules before creating custom exclusions. To review, do the following:
- In the Config Editor, go to Rename > Built-In Rules.
- Select the rule from the list and review the description of the rule.
- Check or uncheck the rules based on your needs.
The exact definitions of all rules are in the file beginning with dotfuscatorReferenceRule in your installation location's Common subdirectory.
For example, the rule Methods with System.Web.Services attributes translates to the following custom rule in C:\Program Files (x86)\PreEmptive Protection Dotfuscator Professional A.B.C\Common :
<excludelist>
<type name=".*" regex="true" excludetype="false">
<comment>Exclude all methods that are decorated with attributes from the System.Web.services namespace.</comment>
<method name=".*" regex="true">
<customattribute name="System.Web.Services.*" regex="true" />
</method>
</type>
</excludelist> Choosing an Exclusion Strategy
Use the following guidelines when selecting an exclusion approach:
| Scenario | Recommended Approach |
| One or two specific members require their original names | Specific Exclusions |
| Multiple related types or members require exclusions | Custom Exclusion Rules |
| A supported framework or library is affected | Built-In Rules |
In many applications, a combination of these approaches provides the best results.
Expanding Exclusions
Avoid excluding large portions of an application unless necessary.
Every exclusion reduces the effectiveness of renaming by preserving information that could otherwise be obfuscated.
When troubleshooting a renaming issue:
- Identify the functionality that is affected.
- Determine which names must remain unchanged.
- Exclude only the required code elements.
- Rebuild and retest the application.
- Expand exclusions only when necessary.