How to obfuscate a WPF app without breaking XAML data binding
A step-by-step guide to protecting a WPF desktop application with Nebula.NET — and keeping bindings, commands and converters working.
WPF apps are a common obfuscation target — they ship to end users’ machines, so the IL is right there to decompile. The one thing to get right is that XAML binds to your view-models by name at runtime, so those names have to survive. Here’s the whole process.
Why WPF needs a little care
When you write {Binding CustomerName} or Command="{Binding SaveCommand}", WPF resolves CustomerName and SaveCommand by name at runtime via reflection. If obfuscation renames those properties to a and b, the binding silently fails — you get a blank field or a dead button, with a binding error in the debug output.
Everything else — your business logic, algorithms, services — has no such constraint and can be fully renamed, flattened and encrypted.
Step 1 — preserve what XAML binds to
The simplest, safest setting for a WPF app is preserve public API, because bound view-model members are usually public:
{
"inputs": ["bin/Release/net8.0/MyApp.dll"],
"outputDirectory": "protected",
"preservePublicApi": true,
"controlFlowObfuscation": true,
"encryptStrings": true
}
If a bound member isn’t public, exclude the view-model explicitly instead of leaving names exposed everywhere:
{ "exclude": ["MyApp.ViewModels.MainViewModel"] }
Nebula also auto-detects most reflection and serialization usage, so converters and types referenced with {x:Type} are generally preserved for you. See Keeping your app working.
Step 2 — obfuscate the internals hard
Your public view-model surface stays named, but the code behind it is where the value is — so lean on control flow and string encryption there. With preservePublicApi on, private and internal members are still renamed, and control-flow flattening applies everywhere.
Step 3 — run it and click through
This is the real test. Obfuscate, launch the protected build, and exercise the screens — especially anything data-bound. If a field is blank or a command is dead, check the debug output for a binding error naming the member, then add that member (or its view-model) to exclude.
Step 4 — sign it for distribution
Desktop users will hit a “Windows protected your PC / Unknown publisher” prompt on an unsigned installer. Sign the protected output with your Authenticode certificate (Nebula can apply it as part of the run) or distribute through the Microsoft Store. See Protecting different project types.
Summary
- Keep
preservePublicApion so bound members survive. - Exclude any non-public view-model that XAML binds to.
- Let control-flow + string encryption protect the internals.
- Run the app and click through the bound screens as your acceptance test.
- Sign the result before you ship it.
Ready to try it? Download Nebula.NET free and protect your first WPF build in a few minutes.
Try Nebula.NET
Harden your .NET code in minutes — start with the free edition.