Json.NET Serializer

Project Hosting
NuGet Package NServiceBus.Newtonsoft.Json (2-pre)
Target NServiceBus Version: 7.x
This page targets a pre-release version and is subject to change prior to the final release.

Using JSON via a NuGet dependency on Json.NET.

How the NServiceBus core uses Json.net

The core of NServiceBus uses Json.net. However it is ILMerged where this library has a standard dll and NuGet dependency. While ILMerging reduces versioning issues in the core it does cause several restrictions:

  • Can't use a different version of Json.net
  • Can't use Json.net attributes
  • Can't customize the Json.net serialization behaviors.

These restrictions do not apply to this serializer.

Usage

endpointConfiguration.UseSerialization<NewtonsoftSerializer>();

Json.net attributes

Json.net attributes are supported.

For example

[JsonObject(MemberSerialization.OptIn)]
public class CreatePersonMessage :
    IMessage
{
    // "John Smith"
    [JsonProperty]
    public string Name { get; set; }

    // "2000-12-15T22:11:03"
    [JsonProperty]
    public DateTime BirthDate { get; set; }

    // new Date(976918263055)
    [JsonProperty]
    [JsonConverter(typeof(JavaScriptDateTimeConverter))]
    public DateTime LastModified { get; set; }

    // not serialized because mode is opt-in
    public string Department { get; set; }
}

Custom Settings

Customizes the instance of JsonSerializerSettings used for serialization.

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    Converters =
    {
        new IsoDateTimeConverter
        {
            DateTimeStyles = DateTimeStyles.RoundtripKind
        }
    }
};
var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.Settings(settings);

Custom Reader

Customize the creation of the JsonReader.

var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.ReaderCreator(stream =>
{
    var streamReader = new StreamReader(stream, Encoding.UTF8);
    return new JsonTextReader(streamReader);
});

Custom Writer

Customize the creation of the JsonWriter.

var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.WriterCreator(stream =>
{
    var streamWriter = new StreamWriter(stream, Encoding.UTF8);
    return new JsonTextWriter(streamWriter)
    {
        Formatting = Formatting.None
    };
});

Custom Content Key

When using additional deserializers or transitioning between different versions of the same serializer it can be helpful to take explicit control over the content type a serializer passes to NServiceBus (to be used for the ContentType header).

var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.ContentTypeKey("custom-key");

BSON

Customize to use the Newtonsoft Bson serialization.

var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.ReaderCreator(stream => new BsonDataReader(stream));
serialization.WriterCreator(stream => new BsonDataWriter(stream));

Compatibility with the core JSON serializer

The only incompatibility with the core serializer is that this serializer does not support the serialization of XContainer and XDocument properties. If XML properties are required on messages strings should be used instead. If XContainer and XDocument properties are required use a JsonConverter.

This serializer is not compatible with multiple bundled messages (when using the Send(object[] messages) APIs) sent from Versions 3 and below of NServiceBus. If this scenario is detected then an exception with the following message will be thrown:

Multiple messages in the same stream are not supported.

The AddDeserializer API can help transition between serializers. See the Multiple Deserializers Sample for more information.

Use a JsonConverter for XContainer and XDocument

The JsonConverter

This is a custom JsonConverter that replicates the approach used by the core serializer.

using NewtonsoftJsonSerializer = global::Newtonsoft.Json.JsonSerializer;

class XmlJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, NewtonsoftJsonSerializer serializer)
    {
        var container = (XContainer) value;
        writer.WriteValue(container.ToString(SaveOptions.DisableFormatting));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, NewtonsoftJsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }

        if (reader.TokenType != JsonToken.String)
        {
            throw new Exception($"Unexpected token or value when parsing XContainer. Token: {reader.TokenType}, Value: {reader.Value}");
        }

        var value = (string) reader.Value;
        if (objectType == typeof(XDocument))
        {
            try
            {
                return XDocument.Load(new StringReader(value));
            }
            catch (Exception exception)
            {
                throw new Exception($"Error parsing XContainer string: {reader.Value}", exception);
            }
        }

        return XElement.Load(new StringReader(value));
    }


    public override bool CanConvert(Type objectType)
    {
        return typeof(XContainer).IsAssignableFrom(objectType);
    }
}

Use the JsonConverter

At configuration time the JsonConverter can then be used with the following.

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    Converters =
    {
        new XmlJsonConverter()
    }
};
var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
serialization.Settings(settings);

Samples


Last modified