Serialising constructor-less .NET types (e.g. MailAddress) using Newtonsoft.Json.JsonConvert in the Json.NET library

Newtonsoft’s Json.NET library is brilliant for serialising .NET objects into JSON and back again. However, there are some things it can’t do. For instance, if we try serialising an object based on the following class:

using System.Net.Mail;

namespace JsonConvertors
{
    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public MailAddress EmailAddress { get; set; }
    }
}

…using the following code:

var person = new Person
{
    FirstName = "Joe",
    LastName = "Bloggs",
    EmailAddress = new MailAddress("joe@bloggs.com"),
};

var json = JsonConvert.SerializeObject(person);
var personCopy = JsonConvert.DeserializeObject<Person>(json);

We get the following nasty error:

Unable to find a constructor to use for type System.Net.Mail.MailAddress. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'EmailAddress.DisplayName', line 1, position 69.

Why Microsoft didn’t add a constructor to the MailAddress type is beyond me. Of course, we could just store the EmailAddress as a string and bypass the issue that way, but I am a firm believer that everything should be strongly typed. Fortunately, we can use the JsonConverter class to tell JsonConvert how to handle constructor-less types like MailAddress.

Here’s how to write a converter for the MailAddress type:

using System;
using System.Net.Mail;
using Newtonsoft.Json;

namespace JsonConvertors
{
    public class MailAddressConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var mailAddress = value as MailAddress;
            writer.WriteValue(mailAddress == null? string.Empty : mailAddress.ToString());
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var text = reader.Value as string;
            MailAddress mailAddress;

            return IsValidMailAddress(text, out mailAddress) ? mailAddress : null;
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(MailAddress);
        }

        private static bool IsValidMailAddress(string text, out MailAddress value)
        {
            try
            {
                value = new MailAddress(text);
                return true;
            }
            catch
            {
                value = null;
                return false;
            }
        }
    }
}

Note that care has been taken to handle null and non-convertible values.

Then simply add the following attribute to your Person class:

using System.Net.Mail;
using Newtonsoft.Json;

namespace JsonConvertors
{
    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        [JsonConverter(typeof(MailAddressConverter))]
        public MailAddress EmailAddress { get; set; }
    }
}

…and the conversion will work like a charm.