patridge patridge - 4 months ago 49
C# Question

How do I serialize IHtmlString to JSON with Json.NET?

I have a field containing raw HTML published via JSON that was recently converted from a string to an IHtmlString. When that change happened, the field went from being a JSON string to being an empty object and a bunch of things consuming that JSON started blowing up.

// When it was a string...
{
someField: "some <span>html</span> string"
}

// When it became an IHtmlString...
{
someField: { }
}


Ignoring any arguments against raw HTML in JSON since it is moot for this project, how do I get the expected string in my JSON serialization?

Answer

Background

Both Json.NET and the default .NET JavaScriptSerializer will treat instances of IHtmlString as an object with no properties and serialize it into an empty object. Why? Because it is an interface with only one method and methods don't serialize to JSON.

public interface IHtmlString {
    string ToHtmlString();
}

Solution

For Json.NET, you will need to create a custom JsonConverter that will consume an IHtmlString and output the raw string.

public class IHtmlStringConverter : Newtonsoft.Json.JsonConverter {
    public override bool CanConvert(Type objectType) {
        return typeof(IHtmlString).IsAssignableFrom(objectType);
    }

    public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) {
        IHtmlString source = value as IHtmlString;
        if (source == null) {
            return;
        }

        writer.WriteValue(source.ToString());
    }

    public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) {
        // warning, not thoroughly tested
        var html = reader.Value as string;
        return html == null ? null : System.Web.Mvc.MvcHtmlString.Create(html);
    }
}

With that in place, send an instance of your new IHtmlStringConverter to Json.NET's SerializeObject call.

string json = JsonConvert.SerializeObject(objectWithAnIHtmlString, new[] { new IHtmlStringConverter() });

Sample Code

For an example MVC project where a controller demos this, head over to this question's GitHub repository.