# 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:

Reflection scenario What happens after renaming?
Type.GetType("MyApp.Services.EmailService") or Assembly.GetType(...) The string literal no longer matches the obfuscated type name, so null is returned; subsequent calls throw NullReferenceException or TypeLoadException.
Activator.CreateInstance("MyApp", "EmailService") Same as above.
typeof(Foo).GetMethod("SendEmail") or LINQ-to-Entities mapping strings The member is now a, b, … so reflection cannot locate the method or property.
nameof(SomeProperty) persisted to config, JSON, or XAML At compile time nameof still gives the pre-obfuscated text; after deployment the runtime knows only the scrambled name.
Custom attributes that embed names (e.g., [Route("api/Users/{userId}")]) and are inspected at runtime Framework looks for a method called GetUsers but finds c.

In short, any string-based reference to metadata breaks once those identifiers are no longer the same.

⚠️ .NET Reactor detects fully-qualified type names and rewrite those literals to the new obfuscated names automatically. If you always pass the full name (e.g., "MyApp.Services.EmailService, MyApp"), Type.GetType will still succeed after obfuscation. This auto-fixing does not help with partial names, member names, or values that are built at run time, so the guidelines below remain essential.


# Fixing it with System.Reflection.ObfuscationAttribute

.NET ships an attribute that .NET Reactor understand: System.Reflection.ObfuscationAttribute.
You decorate exactly the types or members that must stay intact.

# Common attribute properties

Property Meaning
Exclude = true (default) Do not obfuscate this item.
ApplyToMembers = true Extend the rule to all nested members (methods, properties, fields) of the attributed type.
StripAfterObfuscation = true (default) Remove the attribute itself from the final assembly so attackers don’t see your rules.

# 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

  1. Audit reflection usage — Search for .GetType(..), Activator.CreateInstance(..), GetMethod(..), nameof(..), [Route(..)], resource look-ups, XAML bindings, etc.
  2. Categorize — Decide whether to allow renaming and patch code (e.g., use typeof(T) instead of strings) or keep original names.
  3. Annotate — Add ObfuscationAttribute where keeping names is simpler than refactoring.
  4. Automated test pass — Run integration tests against the obfuscated build—reflection issues often surface immediately as TypeLoadException or 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.

See also: Advanced Rules Editor, Declarative Protection