Exclusions Guide

Most .NET code obfuscates without any configuration. Demeanor analyzes your IL at obfuscation time and automatically preserves symbols that would break if renamed — including EF Core entities, WPF data-bound properties, Blazor component parameters, and JSON-serialized types.

Obfuscation and reflection are fundamentally in tension: obfuscation renames symbols, while reflection resolves them by name at runtime. Demeanor bridges this gap with built-in intelligence that detects and adapts to the most common reflection patterns automatically — EF Core, Blazor, WPF data binding, JSON serialization, and more. For frameworks not covered by auto-detection, Demeanor provides simple exclusion mechanisms ([Obfuscation] attributes, --exclude, regex patterns) that let you protect specific symbols while keeping everything else fully obfuscated.

What Works Out of the Box

The following frameworks have been tested against Demeanor and work with zero configuration:

  • Entity Framework Core — Demeanor detects property references in LINQ expression trees and automatically preserves entity types and their properties. All CRUD operations, navigation properties, and queries work after obfuscation.
  • Console and CLI applications — no reflection-sensitive patterns; fully obfuscated.
  • gRPC / Protobuf — generated code uses field numbers, not names.
  • NativeAOT — obfuscation runs on IL before AOT compilation.

Automatic Detection

Demeanor's static analysis scans every method body in your assembly and automatically preserves symbols that would break if renamed:

  • Entry pointsMain methods, module initializers
  • Public/protected API — preserved in library DLLs (unless --include-publics)
  • Expression tree references — properties used in LINQ expressions and EF Core lambdas
  • INotifyPropertyChanged — properties passed to OnPropertyChanged(nameof(...))
  • Blazor component parameters — properties with [Parameter], [CascadingParameter], [Inject], or [SupplyParameterFromQuery]
  • JSON serialization — types passed to JsonSerializer.Serialize<T>() or Deserialize<T>(); types with [JsonSerializable], [DataContract], or [JsonObject]
  • Serialization attributes — properties with [JsonPropertyName], [DataMember], [JsonProperty], [XmlElement], [Column], etc.
  • Reflection string patternsType.GetMethod("Name"), Enum.Parse, etc.
  • WPF/WinForms data binding — properties referenced in PropertyChangedEventArgs, SetBinding, BindingSource patterns
  • COM interop[ComVisible], [ComImport], tdImport flag
  • Dynamic dispatch — DLR Binder.InvokeMember calls
  • Compiler-generated types — async state machines, lambda closures

This detection runs at obfuscation time with zero runtime overhead — no agents, no instrumentation, no phone-home.

Exclusion Mechanisms

[Obfuscation] Attribute (recommended)

The standard .NET attribute for controlling obfuscation. Works with any ECMA-335 compliant obfuscator.

// Exclude a single type
[Obfuscation(Exclude = true)]
public class MyApiResponse { ... }

// Exclude a type and all its members
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public class MyDataContract { ... }

// Exclude a single member
public class Settings
{
    [Obfuscation(Exclude = true)]
    public string ConnectionString { get; set; }
}

Name Exclusions (--exclude)

demeanor --exclude "MyApp.Models.ApiResponse" MyApp.dll

MSBuild (semicolon-separated):

<ObfuscateExclude>MyApp.Models.ApiResponse;MyApp.Services.PaymentService</ObfuscateExclude>

Regex Exclusions (--xr)

demeanor --xr ".*ViewModel$" --xr ".*Controller$" MyApp.dll

MSBuild:

<ObfuscateExcludeRegex>.*ViewModel$;.*Controller$</ObfuscateExcludeRegex>

Category Exclusions

Disable renaming for entire symbol categories: --no-types, --no-methods, --no-fields, --no-properties, --no-events, --no-parameters, --no-enumerations, --no-resource-names.

Framework Guide: Tested Results

Every example below was tested by building a real sample app, obfuscating it with Enterprise-tier Demeanor, and verifying the result. Sample apps are in the samples/ directory of the Demeanor repository.

Entity Framework Core — Just Works

EF Core uses expression tree lambdas for model configuration and queries. Demeanor's ReflectionAnalyzer detects property references in expression trees and automatically preserves entity types and their properties. No exclusions needed.

YOUR CODE
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public List<Order> Orders { get; set; }
}

// Fluent API uses expression trees
modelBuilder.Entity<Customer>(e =>
{
    e.HasKey(c => c.Id);
    e.Property(c => c.Name).HasMaxLength(200);
    e.HasMany(c => c.Orders)
     .WithOne(o => o.Customer);
});
AFTER OBFUSCATION
// Entity types PRESERVED automatically:
// EfCoreSample.Customer (not renamed)
// EfCoreSample.Order (not renamed)
// EfCoreSample.OrderItem (not renamed)
//
// Properties preserved: Id, Name, Email,
//   Orders, Customer, OrderDate, Total, etc.
//
// Internal methods, fields, and
// non-entity types: fully obfuscated.
//
// Result: app runs identically.
// Zero exclusions needed.

Tested with samples/EfCoreSample using SQLite in-memory database. All CRUD operations, navigation properties, LINQ queries, and enum filtering work after obfuscation with zero exclusions.

WPF / MVVM — Properties Preserved, Types Need Exclusion

Demeanor's PropertyUsageAnalyzer detects INotifyPropertyChanged patterns and automatically preserves data-bound properties. However, XAML's x:Class directive references types by fully-qualified name in compiled BAML — type renaming breaks this.

YOUR CODE
public class CustomerViewModel
    : INotifyPropertyChanged
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Summary => ...;
    public ICommand SaveCommand => ...;
}

<!-- XAML binding -->
<TextBox Text="{Binding Name}" />
<Button Command="{Binding SaveCommand}" />
AFTER OBFUSCATION
// Properties PRESERVED automatically:
//   Name, Email, Summary, SaveCommand
//   (0 of 4 properties renamed)
//
// Types renamed: 6 of 6 (100%)
// Fields renamed: 6 of 6 (100%)
// Methods renamed: 21 of 25 (84%)
//
// Problem: XAML x:Class="WpfSample
//   .MainWindow" references the old
//   type name — now renamed to "d".
//   The app won't load the Window.

Solution: Exclude Window and UserControl types from type renaming:

demeanor --xr ".*Window$" --xr ".*UserControl$" --include-publics MyWpfApp.dll

Or in MSBuild:

<ObfuscateExcludeRegex>.*Window$;.*UserControl$</ObfuscateExcludeRegex>

Data binding properties are automatically preserved. Only the type names need exclusion because BAML references them by string name. Internal logic, fields, and non-UI types are fully obfuscated.

ASP.NET Core / Minimal API — Routes Work, DTOs Need Attention

Minimal API routes, middleware, and dependency injection all survive obfuscation — they use delegates and types, not string names. The concern is JSON-serialized response types: System.Text.Json resolves property names via reflection.

YOUR CODE
app.MapGet("/weather", () =>
    new WeatherForecast(
        DateOnly.FromDateTime(DateTime.Now),
        22, "Warm"));

public record WeatherForecast(
    DateOnly Date,
    int TemperatureC,
    string? Summary)
{
    public int TemperatureF =>
        32 + (int)(TemperatureC / 0.5556);
}
AFTER OBFUSCATION
// Routes work: MapGet delegates survive
// DI works: GreetingService injected
//
// Problem: WeatherForecast properties
// renamed. JSON output changes from:
//   {"date": "...", "temperatureC": 22}
// to:
//   {"a": "...", "b": 22}
//
// API consumers break.

Solution: Use [JsonPropertyName] to fix JSON names (best practice regardless of obfuscation):

using System.Text.Json.Serialization;

public record WeatherForecast(
    [property: JsonPropertyName("date")] DateOnly Date,
    [property: JsonPropertyName("temperatureC")] int TemperatureC,
    [property: JsonPropertyName("summary")] string? Summary);

Or exclude the DTO type:

[Obfuscation(Exclude = true, ApplyToMembers = true)]
public record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary);

Using [JsonPropertyName] is the better approach — it makes your API contract explicit and survives refactoring even without obfuscation.

Blazor — Routes Work, [Parameter] Properties Need Exclusion

Blazor routing uses [Route] attributes which survive obfuscation. Component type names can be renamed. But [Parameter] properties on components are resolved by string name during rendering — they must be preserved.

YOUR CODE
<!-- GreetingCard.razor -->
<div class="card">
    <h3>@Name</h3>
    <p>@Message</p>
    <button @onclick="OnDismiss">
        Dismiss
    </button>
</div>

@code {
    [Parameter]
    public string Name { get; set; }
    [Parameter]
    public string Message { get; set; }
    [Parameter]
    public EventCallback OnDismiss { get; set; }
}
AFTER OBFUSCATION
// Routes preserved: [RouteAttribute]
//   survives on renamed component types.
// Type names renamed (fine — Blazor
//   discovers by [Route], not by name).
//
// Problem: [Parameter] properties
//   Name, Message, OnDismiss renamed.
//   Parent component still emits
//   AddComponentParameter("Name", ...)
//   but property is now called "a".
//   Parameters silently ignored.

Solution: Exclude [Parameter] properties. The simplest approach is to exclude all Blazor component types:

demeanor --xr ".*ComponentBase$" --include-publics MyBlazorApp.dll

Or use the attribute on individual components:

[Obfuscation(Exclude = true, ApplyToMembers = true)]
public partial class GreetingCard : ComponentBase { ... }

A future Demeanor update will automatically detect [Parameter], [CascadingParameter], and [Inject] attributes and preserve those properties. Internal component logic (private fields, methods, event handlers) is safely obfuscated.

Quick Reference

FrameworkStatusExclusions Needed
EF CoreJust worksNone — expression trees auto-detected
Console / CLI appsJust worksNone
ASP.NET Minimal APIRoutes + DI work[JsonPropertyName] on response DTOs
WPF / MVVMProperties auto-preservedExclude Window/UserControl types: --xr ".*Window$"
BlazorRoutes workExclude [Parameter] component types
WinFormsMostly works--xr ".*Form$" --xr ".*UserControl$"
System.Text.JsonWorks with attributes[JsonPropertyName] or exclude type
Newtonsoft.JsonWorks with attributes[JsonProperty] or exclude type
gRPC / ProtobufJust worksGenerated code uses field numbers, not names
NativeAOTJust worksObfuscation runs on IL before AOT compilation