10

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

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Buda Gavril
  • 21,409
  • 40
  • 127
  • 196
  • I wouldn't expect so - I'd expect it to encode strings *in JSON terms*. It would be very odd for it to *HTML-encode* the content. A JSON serializer's job is to get data from X to Y as JSON... for it to perform HTML encoding feels like massive scope creep. – Jon Skeet May 22 '17 at 14:52
  • Why not create a method where you pass in the object to be serialized and it returns an html encoded string result? – user1628733 May 22 '17 at 14:52
  • Is it what you have asked? [encoding](https://stackoverflow.com/questions/14106894/how-to-use-json-net-stringescapehandling-escapenonascii) – Artyom May 22 '17 at 14:54
  • @Artyom Yes, thank you, this was what I was looking for. Thank you – Buda Gavril May 22 '17 at 15:04

3 Answers3

12

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

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
12

Try this:

var json = JObject.Parse("{'Name':'<script>alert(1);</script>'}");
var serializerSettings = new JsonSerializerSettings()
{
    StringEscapeHandling = StringEscapeHandling.EscapeHtml
};
var result = JsonConvert.SerializeObject(json, serializerSettings);

result will be:

{"Name":"\u003cscript\u003ealert(1);\u003c/script\u003e"}
Mohammad Nikravan
  • 1,543
  • 2
  • 19
  • 22
  • This doesn't encode strings in the same way that `@Html.Encode()` does, but I found it helpful for my use case – Kevin Secrist May 14 '18 at 18:20
  • If your escaped HTML per above is loaded into eval contexts such as jQuery.html function, the script will be executed. Http Utility HTML encode is better. – gls123 Jun 11 '19 at 19:51
  • Not answering the question, but exactly what I needed :D – HelloWorld Sep 14 '20 at 07:58
0

I found a very simple way doing this (WebAPI2).

When you set your object properties, just encode it with below.

myObject.encoded_field = HttpUtility.HtmlEncode(your_html_content)

BenW
  • 1,393
  • 1
  • 16
  • 26