重置Json.NET契约缓存:自定义解析器动态属性更新失效问题
Hey there, I've run into this exact problem before—Json.NET's contract caching is great for performance, but it's a real pain when your dynamic property configurations change mid-app lifecycle. Let's break down how to fix this:
Option 1: Clear the Built-in Cache (Quick Fix)
The DefaultContractResolver stores generated contracts in a private _contractCache dictionary. Since it's private, we'll need reflection to wipe it clean:
// Grab your custom resolver instance (make sure this is the same one used in your serialization setup!) var customResolver = new YourCustomContractResolver(); // Use reflection to access the private cache field var contractCacheField = typeof(DefaultContractResolver) .GetField("_contractCache", BindingFlags.Instance | BindingFlags.NonPublic); if (contractCacheField != null) { var cache = contractCacheField.GetValue(customResolver) as IDictionary; cache?.Clear(); }
After running this, the next time Json.NET needs to resolve a contract for your type, it'll re-run your CreateObjectContract method with the updated property list.
Option 2: Build a Cacheable Resolver (Long-Term Solution)
If you're regularly updating property configurations, it's better to take control of the cache yourself instead of relying on Json.NET's internal implementation. Here's how to create a resolver with a public reset method:
public class DynamicContractResolver : DefaultContractResolver { // Our own cache dictionary we can fully control private readonly Dictionary<Type, JsonContract> _customContractCache = new(); protected override JsonContract ResolveContract(Type type) { // Check our custom cache first if (_customContractCache.TryGetValue(type, out var existingContract)) { return existingContract; } // Generate and cache a new contract if needed var newContract = base.ResolveContract(type); _customContractCache[type] = newContract; return newContract; } // Public method to reset the cache whenever your properties change public void ResetContractCache() { _customContractCache.Clear(); } protected override JsonObjectContract CreateObjectContract(Type objectType) { var contract = base.CreateObjectContract(objectType); AddSomeMorePropertiesToContract(contract, objectType); return contract; } private void AddSomeMorePropertiesToContract(JsonObjectContract contract, Type objectType) { // Your logic to add/remove dynamic properties here } }
Now whenever your property list changes, just call dynamicResolver.ResetContractCache()—no reflection hacks needed, and you're insulated from future Json.NET internal changes.
Quick Notes
- If you're using a global resolver via
JsonConvert.DefaultSettings, make sure you're referencing the same instance when resetting the cache (don't create a new one!). - The reflection approach works but is fragile—it depends on Json.NET's internal field names. Stick with the custom cache approach for production code.
内容的提问来源于stack exchange,提问作者Alwin S

