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

PropertyCLIDefaultDescription
<Obfuscate>true on Release; false on Debug or when IsTestProject=trueMaster switch. Auto-enables for Release builds. Set to false to disable, or true to obfuscate every config.
<DemeanorIncludePublics>--include-publicsfalseAlso obfuscate public/protected symbols. Use for executables; omit for libraries.
<DemeanorIncludeDeps>--include-depsfalseAlso obfuscate co-located private dependencies.

Naming

PropertyCLIDefaultDescription
<DemeanorNamingMode>--namesAlphaAlpha (a, b, c) or Unicode (whitespace/invisible chars).
<DemeanorNamespacePrefix>--prefix(none)Namespace prefix for renamed types. Prevents cross-assembly name collisions.
<DemeanorNoAggressive>--no-aggressivefalseDisable aggressive mode (property/event metadata stripping, etc.).
<DemeanorNoVirtualRename>--no-virtual-renamefalseSkip renaming virtual method overrides.
<DemeanorNoEnumDeletion>--no-enum-deletionfalsePreserve enum literal field metadata.

Protection Toggles

PropertyCLIDefaultDescription
<DemeanorNoStrings>--no-stringsfalseDisable string encryption.
<DemeanorNoConstants>--no-constantsfalseDisable integer constant encryption.
<DemeanorNoResources>--no-resourcesfalseDisable resource encryption.
<DemeanorNoCallHiding>--no-call-hidingfalseDisable call hiding.
<DemeanorProxyThreshold>--proxy-threshold16Minimum method body size (bytes) eligible for call hiding.
<DemeanorCfgLevel>--cfgFlattenControl flow level: Reorder, Predicates, or Flatten.
<DemeanorNoCfg>--no-cfgfalseDisable control flow obfuscation entirely.
<DemeanorNoHinderReflection>--no-hinder-reflectionfalseDisable reflection hindrance metadata.
<DemeanorNoAntiTamper>--no-anti-tamperfalseDisable anti-tamper integrity verification.
<DemeanorNoAntiDebug>--no-anti-debugfalseDisable 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).

PropertyCLIDescription
<DemeanorNoTypes>--no-typesDon’t rename types.
<DemeanorNoMethods>--no-methodsDon’t rename methods.
<DemeanorNoFields>--no-fieldsDon’t rename fields.
<DemeanorNoProperties>--no-propertiesDon’t rename properties.
<DemeanorNoEvents>--no-eventsDon’t rename events.
<DemeanorNoParameters>--no-parametersDon’t rename parameters.
<DemeanorNoEnumerations>--no-enumerationsDon’t rename enum members.
<DemeanorNoResourceNames>--no-resource-namesDon’t rename embedded resources.
<DemeanorNoSerializable>--no-serializablePreserve names of [Serializable] types and their fields.

Reporting & Incremental Builds

PropertyCLIDefaultDescription
<DemeanorReport>--reporttrueEmit 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

PropertyCLIDefaultDescription
<DemeanorSatelliteAssemblies>--satellite-assembliesfalseRename 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

PropertyCLIDescription
<DemeanorKeyFile>--keyfilePath to a .snk or .pfx file for strong-name re-signing.
<DemeanorKeyContainer>--keycontainerNamed key container for strong-name re-signing.

Output Control

PropertyCLIDefaultDescription
<DemeanorQuiet>--quiettrueSuppress non-error output. Set to false for verbose CI logs.
<DemeanorVerbose>--verbosefalsePer-phase stats and full stack traces on error.
<DemeanorDebug>--debugfalsePreserve 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 GroupCLIDescription
<DemeanorExclude>--excludeFully-qualified type name to exclude.
<DemeanorExcludeRegex>--xrRegex pattern for types to exclude.
<DemeanorExcludeAssembly>--xaAssembly name to skip entirely.
<DemeanorAddAssembly>--add-assemblyInclude 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.