StackOverflow Q32562381

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
					
public class Program
{
	public static void Main()
	{
        string json = @"
        { 
            ""Name"" : ""<b>Foo Bar</b>"", 
            ""Description"" : ""<p>Bada Boom Bada Bing</p>"", 
        }";

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CustomResolver()
        };

        Foo foo = JsonConvert.DeserializeObject<Foo>(json, settings);
        Console.WriteLine("Name: " + foo.Name);
        Console.WriteLine("Desc: " + foo.Description);
	}
}


class Foo
{
    public string Name { get; set; }
    [AllowHtml]
    public string Description { get; set; }
}


class AllowHtmlAttribute : Attribute 
{ 
}


public class CustomResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);

        // Find all string properties that do not have an [AllowHtml] attribute applied
        // and attach an HtmlEncodingValueProvider instance to them
        foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
        {
            PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
            if (pi != null && pi.GetCustomAttribute(typeof(AllowHtmlAttribute), true) == 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)
        {
            var encoded = AntiXssEncoder.HtmlEncode((string)value, useNamedEntities: true);
            targetProperty.SetValue(target, encoded);
        }

        // 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)
        {
            return targetProperty.GetValue(target);
        }
    }
}



// Note: Following is a stand-in for the System.Web.Security.AntiXss.AntiXssEncoder class,
// as dotnetfiddle apparently does not provide access to the System.Web.Security namespace.
// In your production code, please use the real version provided by .NET; do NOT use this stand-in class.
public static class AntiXssEncoder
{
    public static string HtmlEncode(string s, bool useNamedEntities)
	{
		if (s != null)
		{
			// \u0026 is an ampersand; needed here to get around a dotnetfiddle bug
			s = s.Replace("\u0026", "\u0026amp;").Replace("<", "\u0026lt;").Replace(">", "\u0026gt;");
		}
		return s;
	}
}
;