MSBuild Integration
The WiseOwl.Demeanor.MSBuild NuGet package runs obfuscation as a post-build step. It bundles its own obfuscator binary — the global CLI tool does not need to be installed on the build machine.
Every CLI option has a corresponding MSBuild property. Set them in your .csproj and they apply on every Release build.
Quick setup
dotnet add package WiseOwl.Demeanor.MSBuild
dotnet build -c Release
That’s it. Release builds auto-obfuscate. Debug builds and test projects (anything where IsTestProject=true, set automatically by Microsoft.NET.Test.Sdk) are auto-skipped — obfuscating an xunit / mstest / nunit assembly would break the runner’s reflection-based discovery.
Override the default
<PropertyGroup>
<!-- Disable obfuscation entirely (any config): -->
<Obfuscate>false</Obfuscate>
<!-- Or obfuscate Debug builds too: -->
<Obfuscate>true</Obfuscate>
</PropertyGroup>
Scope
| Property | CLI | Default | Description |
<Obfuscate> | — | true on Release; false on Debug or when IsTestProject=true | Master switch. Auto-enables for Release builds. Set to false to disable, or true to obfuscate every config. |
<DemeanorIncludePublics> | --include-publics | false | Also obfuscate public/protected symbols. Use for executables; omit for libraries. |
<DemeanorIncludeDeps> | --include-deps | false | Also obfuscate co-located private dependencies. |
Naming
| Property | CLI | Default | Description |
<DemeanorNamingMode> | --names | Alpha | Alpha (a, b, c) or Unicode (whitespace/invisible chars). |
<DemeanorNamespacePrefix> | --prefix | (none) | Namespace prefix for renamed types. Prevents cross-assembly name collisions. |
<DemeanorNoAggressive> | --no-aggressive | false | Disable aggressive mode (property/event metadata stripping, etc.). |
<DemeanorNoVirtualRename> | --no-virtual-rename | false | Skip renaming virtual method overrides. |
<DemeanorNoEnumDeletion> | --no-enum-deletion | false | Preserve enum literal field metadata. |
Protection Toggles
| Property | CLI | Default | Description |
<DemeanorNoStrings> | --no-strings | false | Disable string encryption. |
<DemeanorNoConstants> | --no-constants | false | Disable integer constant encryption. |
<DemeanorNoResources> | --no-resources | false | Disable resource encryption. |
<DemeanorNoCallHiding> | --no-call-hiding | false | Disable call hiding. |
<DemeanorProxyThreshold> | --proxy-threshold | 16 | Minimum method body size (bytes) eligible for call hiding. |
<DemeanorCfgLevel> | --cfg | Flatten | Control flow level: Reorder, Predicates, or Flatten. |
<DemeanorNoCfg> | --no-cfg | false | Disable control flow obfuscation entirely. |
<DemeanorNoHinderReflection> | --no-hinder-reflection | false | Disable reflection hindrance metadata. |
<DemeanorNoAntiTamper> | --no-anti-tamper | false | Disable anti-tamper integrity verification. |
<DemeanorNoAntiDebug> | --no-anti-debug | false | Disable anti-debug detection. |
Category Disabling
Disable renaming of entire symbol categories. Useful when a broad set of symbols must keep their names (e.g., all properties in a heavily serialized app).
| Property | CLI | Description |
<DemeanorNoTypes> | --no-types | Don’t rename types. |
<DemeanorNoMethods> | --no-methods | Don’t rename methods. |
<DemeanorNoFields> | --no-fields | Don’t rename fields. |
<DemeanorNoProperties> | --no-properties | Don’t rename properties. |
<DemeanorNoEvents> | --no-events | Don’t rename events. |
<DemeanorNoParameters> | --no-parameters | Don’t rename parameters. |
<DemeanorNoEnumerations> | --no-enumerations | Don’t rename enum members. |
<DemeanorNoResourceNames> | --no-resource-names | Don’t rename embedded resources. |
<DemeanorNoSerializable> | --no-serializable | Preserve names of [Serializable] types and their fields. |
Reporting & Incremental Builds
| Property | CLI | Default | Description |
<DemeanorReport> | --report | true | Emit a JSON name-mapping report for stack-trace decoding. |
<DemeanorReportFile> | --report-file | (auto) | Custom path for the report file. |
<DemeanorPriorReport> | --prior-report | (none) | Path to a prior version’s report for incremental name stability. |
Satellite Assemblies
| Property | CLI | Default | Description |
<DemeanorSatelliteAssemblies> | --satellite-assemblies | false | Rename resources in culture-specific satellite assemblies to match. |
<DemeanorSaCultures> | --sa-cultures | (all) | Comma-separated list of cultures to process (e.g., fr,de). |
Strong Name Re-Signing
| Property | CLI | Description |
<DemeanorKeyFile> | --keyfile | Path to a .snk or .pfx file for strong-name re-signing. |
<DemeanorKeyContainer> | --keycontainer | Named key container for strong-name re-signing. |
Output Control
| Property | CLI | Default | Description |
<DemeanorQuiet> | --quiet | true | Suppress non-error output. Set to false for verbose CI logs. |
<DemeanorVerbose> | --verbose | false | Per-phase stats and full stack traces on error. |
<DemeanorDebug> | --debug | false | Preserve PDB data in obfuscated output. |
Exclusion Item Groups
To exclude types or assemblies from renaming without modifying source code. [Obfuscation] attributes in source are preferred for long-term maintenance. See the Exclusions Guide.
| Item Group | CLI | Description |
<DemeanorExclude> | --exclude | Fully-qualified type name to exclude. |
<DemeanorExcludeRegex> | --xr | Regex pattern for types to exclude. |
<DemeanorExcludeAssembly> | --xa | Assembly name to skip entirely. |
<DemeanorAddAssembly> | --add-assembly | Include a dynamically referenced assembly. |
Example
<ItemGroup>
<DemeanorExclude Include="MyNamespace.MyType" />
<DemeanorExcludeRegex Include="MyNamespace\.Dtos\..*" />
<DemeanorExcludeAssembly Include="ThirdParty.Library" />
</ItemGroup>
Complete Example
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<!-- Obfuscation auto-enables on Release; no <Obfuscate>true</Obfuscate> needed. -->
<DemeanorIncludeDeps>true</DemeanorIncludeDeps>
<!-- Use incremental builds to preserve name stability -->
<DemeanorPriorReport>$(MSBuildProjectDirectory)\prior.report.json</DemeanorPriorReport>
<!-- Re-sign after obfuscation -->
<DemeanorKeyFile>$(MSBuildProjectDirectory)\MyApp.snk</DemeanorKeyFile>
</PropertyGroup>
<ItemGroup>
<!-- Exclude types that use custom reflection -->
<DemeanorExcludeRegex Include="MyApp\.Plugins\..*" />
</ItemGroup>
Any [Obfuscation] attributes in source carry over automatically — the engine reads them from the assembly metadata.