#
Reflection Problems
#
Why renaming obfuscation breaks code that uses reflection
When you turn on the Obfuscation option, every type, method, property, field, event, parameter, and namespace can be renamed to meaningless identifiers. While this thwarts casual IL inspection, it introduces runtime failures anywhere your program expects the original metadata names to exist.
Typical patterns that fail are:
In short, any string-based reference to metadata breaks once those identifiers are no longer the same.
Limits of automatic name rewriting
.NET Reactor detects fully-qualified type names and rewrites those literals to the new obfuscated names automatically.
If you always pass the full name (for example, "MyApp.Services.EmailService, MyApp"), Type.GetType will still succeed after obfuscation.
This does not help with partial names, member names, or values built at runtime.
#
Fixing it with System.Reflection.ObfuscationAttribute
.NET ships an attribute that .NET Reactor understands: System.Reflection.ObfuscationAttribute.
You decorate exactly the types or members that must stay intact.
#
Common attribute properties
#
At the class level – exclude a whole type (and its members)
using System.Reflection;
namespace MyApp.Services
{
[Obfuscation(ApplyToMembers = true)]
internal class EmailService
{
public void SendEmail(string to, string subject) { … }
}
}
EmailService and everything inside it remain exactly as compiled (EmailService, SendEmail, subject, …).
#
At the method or property level – fine-grained control
internal class ReportBuilder
{
// Only this method keeps its name; the rest of the class can be renamed.
[Obfuscation()]
public string BuildFromTemplate(string templateName) { … }
}
#
Practical checklist
- Audit reflection usage — Search for
.GetType(..),Activator.CreateInstance(..),GetMethod(..),nameof(..),[Route(..)], resource look-ups, XAML bindings, etc. - Categorize — Decide whether to allow renaming and patch code (e.g., use
typeof(T)instead of strings) or keep original names. - Annotate — Add
ObfuscationAttributewhere keeping names is simpler than refactoring. - Automated test pass — Run integration tests against the obfuscated build—reflection issues often surface immediately as
TypeLoadExceptionor binding errors.
By explicitly marking only the reflection-critical hotspots with ObfuscationAttribute, you get the best of both worlds: robust runtime behavior and maximum symbol scrambling everywhere else.
#
WPF and XAML bindings
WPF and other XAML-based UI code can depend on names that are resolved at runtime rather than by normal compiled references. A binding such as Path=CustomerName, a command name, a converter type loaded by name, or configuration that names a view or view model can stop resolving if the corresponding symbol is renamed.
When a protected WPF application loses bindings or UI behavior after enabling obfuscation:
- Confirm that the unprotected build and the protected build with renaming disabled both work.
- Identify properties, commands, types, or members referenced by XAML, binding paths, resources, configuration, or runtime lookup strings.
- Preserve only those required names with
ObfuscationAttribute, Declarative Protection, or an Advanced Rule. - Test the final protected application with the same XAML, resource dictionaries, themes, and view models used in production.
Do not exclude the whole application from renaming unless a narrower rule is impractical. Dynamic XAML or third-party UI frameworks can introduce additional name-based contracts, so integration tests against the protected output are important.
#
Related topics
Advanced Rules Editor, Declarative Protection
JSON serialization ·