Separate wire names from CLR names
JSON consumers depend on the document contract, not your C# spelling. With System.Text.Json, JsonPropertyName gives a property an explicit JSON name. Test both serialization and deserialization: an expected outbound document is only half the contract. This attribute does not promise that every obfuscator preserves every reflection-accessed member, constructor or converter.
Try a small round-trip test
Place the code below in a .NET 8 console project and run it before protection. It must print json-contract=OK. Repeat from a copied output directory after replacing only the application assembly with its protected version. The test verifies a stable order_id name and a successful read back into the DTO. Add cases for your own naming policy, enum representation, constructor selection and custom converters rather than generalizing this tiny result to every DTO.
Inventory names stored as text
Type.GetType strings, GetMethod lookups, configuration entries and plugin discovery can bypass normal compiled references. Do not assume that an obfuscator rewrites arbitrary strings. Prefer explicit registrations or references where possible, but also test the actual production mechanism. Preserving public API names helps a compiled library consumer; it does not guarantee that internal reflective lookups remain valid.
Check both sides of a deployment
Save representative documents from the old release and read them with the protected one. Let an unchanged consumer call the protected DLL, and verify a real plugin and UI screen. Test missing and null values as well as the happy path. Source-generated serialization can reduce some reflection use, but it is not an automatic repair for arbitrary renaming. If a required name cannot be retained with the available options, reduce protection or use a workflow that supports that contract.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public sealed class OrderDto
{
[JsonPropertyName("order_id")]
public int Id { get; set; }
}
public static class Program
{
public static void Main()
{
string json = JsonSerializer.Serialize(new OrderDto { Id = 42 });
var copy = JsonSerializer.Deserialize<OrderDto>(json);
if (json != "{\"order_id\":42}" || copy?.Id != 42)
throw new InvalidOperationException("JSON contract changed");
Console.WriteLine("json-contract=OK");
}
}