Search code examples
c#serializationjson.nethtml-encode

Automatically HtmlEncode strings when the model is serialized with Json.Net


Is there a way to configure Json.Net to automatically encode all strings like HtmlEncode(myString) when the model is serialized?


Solution

  • You could use a solution similar to the one in Selectively escape HTML in strings during deserialization, with a couple of minor changes:

    1. Change the HtmlEncodingValueProvider to apply the encoding in GetValue rather than SetValue (so that it does the encoding on serialization rather than deserialization).
    2. Change the resolver to apply the value provider to all string properties rather than looking for an attribute.

    Here is what the resulting code would look like:

    public class CustomResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
    
            // Attach an HtmlEncodingValueProvider instance to all string properties
            foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
            {
                PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
                if (pi != null)
                {
                    prop.ValueProvider = new HtmlEncodingValueProvider(pi);
                }
            }
    
            return props;
        }
    
        protected class HtmlEncodingValueProvider : IValueProvider
        {
            PropertyInfo targetProperty;
    
            public HtmlEncodingValueProvider(PropertyInfo targetProperty)
            {
                this.targetProperty = targetProperty;
            }
    
            // SetValue gets called by Json.Net during deserialization.
            // The value parameter has the original value read from the JSON;
            // target is the object on which to set the value.
            public void SetValue(object target, object value)
            {
                targetProperty.SetValue(target, (string)value);
            }
    
            // GetValue is called by Json.Net during serialization.
            // The target parameter has the object from which to read the string;
            // the return value is the string that gets written to the JSON
            public object GetValue(object target)
            {
                string value = (string)targetProperty.GetValue(target);
                return System.Web.HttpUtility.HtmlEncode(value);
            }
        }
    }
    

    Use the custom ContractResolver like this:

    var settings = new JsonSerializerSettings
    {
        ContractResolver = new CustomResolver(),
        Formatting = Formatting.Indented
    };
    
    string json = JsonConvert.SerializeObject(your_object, settings);
    

    Fiddle: https://dotnetfiddle.net/RhFlk8