Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NewtonSoft Json serializer performance

Tags:

c#

json.net

I have an object that I am serializing into Json using NewtonSoft Json.Net. The object is relatively large, the resulting Json is about 300kb, but the serialization process takes around 60 seconds.

The objects to be serialized are just plain POCO's.

The code I am using is

string json = Newtonsoft.Json.JsonConvert.SerializeObject(data, Formatting.Indented);

Is there anything that can be done to speed up the serialization, adding attributes etc.

EDIT: I have just tested with ServiceStack.Text Json serializer and that takes 48 seconds, still pretty slow.

[Serializable]
public class AppointmentItemViewModel 
{
    public AppointmentItemViewModel()
    {
        Data = new AppointmentData();
        Statuses = new List<Status>();
        ClosedDays = new List<ClosedDay>();
        OpenHours = new List<OpenHours>();
    }

    public int CurrentDay { get; set; }

    public int CurrentMonth { get; set; }

    public int CurrentYear { get; set; }

    public int Day { get; set; }

    public int Month { get; set; }

    public int Year { get; set; }

    public int FirstHour { get; set; }

    public int LastHour { get; set; }

    public int CurrentHour { get; set; }

    public int Step { get; set; }

    public bool StaffOnlyBookOwn { get; set; }

    public bool AllowPastAppointments { get; set; }

    public bool AllowBlocks { get; set; }

    public bool AllowGoogleCalendarSync { get; set; }

    public long CurrentUser { get; set; }

    public string DebugInfo { get; set; }

    public bool HasResources { get; set; }

    public string OrganisationId { get; set; }

    public string DefaultTab { get; set; }

    public string StartDay { get; set; }

    public bool AppointmentBreaksOnWeek { get; set; }

    public bool AppointmentBreaksOnMonth { get; set; }

    public AppointmentData Data { get; set; }

    public IEnumerable<Status> Statuses { get; set; }

    public IEnumerable<LocationStaff> Staff { get; set; }

    public IEnumerable<ClosedDay> ClosedDays { get; set; }

    public IEnumerable<OpenHours> OpenHours { get; set; }

    public IUserContext UserContext()
    {
        return ServiceLocator.Current.GetInstance<IUserContext>();
    }

    public override string ToString()
    {
        // Serialize the Json
        var sb = new StringBuilder();

        StringWriter sw = new StringWriter(sb);

        using (JsonWriter writer = new JsonTextWriter(sw))
        {
            writer.WriteStartObject();

            WriteProperty(writer, "CurrentDay", this.CurrentDay);
            WriteProperty(writer, "CurrentMonth", this.CurrentMonth);
            WriteProperty(writer, "CurrentYear", this.CurrentYear);
            WriteProperty(writer, "Day", this.Day);
            WriteProperty(writer, "Month", this.Month);
            WriteProperty(writer, "Year", this.Year);
            WriteProperty(writer, "FirstHour", this.FirstHour);
            WriteProperty(writer, "LastHour", this.LastHour);
            WriteProperty(writer, "CurrentHour", this.CurrentHour);
            WriteProperty(writer, "Step", this.Step);
            WriteProperty(writer, "StaffOnlyBookOwn", this.StaffOnlyBookOwn);
            WriteProperty(writer, "AllowPastAppointments", this.AllowPastAppointments);
            WriteProperty(writer, "AllowBlocks", this.AllowBlocks);
            WriteProperty(writer, "AllowGoogleCalendarSync", this.AllowGoogleCalendarSync);
            WriteProperty(writer, "CurrentUser", this.CurrentUser);
            WriteProperty(writer, "HasResources", this.HasResources);
            WriteProperty(writer, "OrganisationId", this.OrganisationId);
            WriteProperty(writer, "DefaultTab", this.DefaultTab);
            WriteProperty(writer, "StartDay", this.StartDay);
            WriteProperty(writer, "AppointmentBreaksOnWeek", this.AppointmentBreaksOnWeek);
            WriteProperty(writer, "AppointmentBreaksOnMonth", this.AppointmentBreaksOnMonth);


            writer.WritePropertyName("Statuses");
            writer.WriteStartArray();
            foreach (var item in this.Statuses)
            {
                writer.WriteStartObject();
                WriteProperty(writer, "Id", item.Id);
                WriteProperty(writer, "Description", item.Description);
                WriteProperty(writer, "Color", item.Color);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();


            writer.WritePropertyName("Staff");
            writer.WriteStartArray();
            foreach (var item in this.Staff)
            {
                writer.WriteStartObject();
                WriteProperty(writer, "Id", item.Id);
                WriteProperty(writer, "Name", item.Name);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();


            writer.WritePropertyName("ClosedDays");
            writer.WriteStartArray();
            foreach (var item in this.ClosedDays)
            {
                writer.WriteStartObject();
                WriteProperty(writer, "Year", item.Year);
                WriteProperty(writer, "Month", item.Month);
                WriteProperty(writer, "Day", item.Day);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();


            writer.WritePropertyName("OpenHours");
            writer.WriteStartArray();
            foreach (var item in this.OpenHours)
            {
                writer.WriteStartObject();
                WriteProperty(writer, "DayOfWeek", item.DayOfWeek);
                WriteProperty(writer, "OpenHour", item.OpenHour);
                WriteProperty(writer, "CloseHour", item.CloseHour);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();

            // Main data
            writer.WritePropertyName("Data");
            writer.WriteStartObject();

            writer.WritePropertyName("Appointments");
            writer.WriteStartArray();
            foreach (var item in this.Data.Appointments)
            {
                writer.WriteStartObject();

                WriteProperty(writer, "Id", item.Id);
                WriteProperty(writer, "AppointmentId", item.AppointmentId);
                WriteProperty(writer, "Year", item.Year);
                WriteProperty(writer, "Month", item.Month);
                WriteProperty(writer, "Day", item.Day);
                WriteProperty(writer, "StartHour", item.StartHour);
                WriteProperty(writer, "StartMinute", item.StartMinute);
                WriteProperty(writer, "EndHour", item.EndHour);
                WriteProperty(writer, "EndMinute", item.EndMinute);
                WriteProperty(writer, "ResourceId", item.ResourceId);
                WriteProperty(writer, "Description", item.Description);
                WriteProperty(writer, "Status", item.Status);
                WriteProperty(writer, "IsClass", item.IsClass);
                WriteProperty(writer, "ProcessingLength", item.ProcessingLength);
                WriteProperty(writer, "ClientId", item.ClientId);
                WriteProperty(writer, "ClientName", item.ClientName);
                WriteProperty(writer, "ClientPhone", item.ClientPhone);
                WriteProperty(writer, "ClientNotes", item.ClientNotes);
                WriteProperty(writer, "ClientHasMobile", item.ClientHasMobile);
                WriteProperty(writer, "ClassFull", item.ClassFull);
                WriteProperty(writer, "ClientWaiting", item.ClientWaiting);
                WriteProperty(writer, "PromotionCode", item.PromotionCode);
                WriteProperty(writer, "ArrivalNote", item.ArrivalNote);
                WriteProperty(writer, "Labels", item.Labels);
                WriteProperty(writer, "ReminderSent", item.ReminderSent);
                WriteProperty(writer, "Cancelled", item.Cancelled);


                writer.WritePropertyName("Items");
                writer.WriteStartArray();
                foreach (var appointmentItem in item.Items)
                {
                    writer.WriteStartObject();
                    WriteProperty(writer, "Name", appointmentItem.Name);
                    WriteProperty(writer, "Length", appointmentItem.Length);
                    WriteProperty(writer, "ProcessingTime", appointmentItem.ProcessingTime);
                    WriteProperty(writer, "Resource", appointmentItem.Resource);
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();

                writer.WriteEndObject();
            }
            writer.WriteEndArray();

            writer.WritePropertyName("Resources");
            writer.WriteStartArray();
            foreach (var item in this.Data.Resources)
            {
                writer.WriteStartObject();

                WriteProperty(writer, "Id", item.Id);
                WriteProperty(writer, "Name", item.Name);
                WriteProperty(writer, "BlockLength", item.BlockLength);
                WriteProperty(writer, "StartHour", item.StartHour);
                WriteProperty(writer, "EndHour", item.EndHour);


                writer.WritePropertyName("Breaks");
                writer.WriteStartArray();
                foreach (var breakItem in item.Breaks)
                {
                    writer.WriteStartObject();
                    WriteProperty(writer, "Year", breakItem.Year);
                    WriteProperty(writer, "Month", breakItem.Month);
                    WriteProperty(writer, "Day", breakItem.Day);
                    WriteProperty(writer, "DayOfWeek", breakItem.DayOfWeek);
                    WriteProperty(writer, "StartHour", breakItem.StartHour);
                    WriteProperty(writer, "StartMinute", breakItem.StartMinute);
                    WriteProperty(writer, "Length", breakItem.Length);
                    WriteProperty(writer, "Description", breakItem.Description);
                    WriteProperty(writer, "OtherBreak", breakItem.OtherBreak);
                    WriteProperty(writer, "UserBreak", breakItem.UserBreak);
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();


                writer.WritePropertyName("OpenCloseBreaks");
                writer.WriteStartArray();
                foreach (var breakItem in item.OpenCloseBreaks)
                {
                    writer.WriteStartObject();
                    WriteProperty(writer, "Year", breakItem.Year);
                    WriteProperty(writer, "Month", breakItem.Month);
                    WriteProperty(writer, "Day", breakItem.Day);
                    WriteProperty(writer, "DayOfWeek", breakItem.DayOfWeek);
                    WriteProperty(writer, "StartHour", breakItem.StartHour);
                    WriteProperty(writer, "StartMinute", breakItem.StartMinute);
                    WriteProperty(writer, "Length", breakItem.Length);
                    WriteProperty(writer, "Description", breakItem.Description);
                    WriteProperty(writer, "OtherBreak", breakItem.OtherBreak);
                    WriteProperty(writer, "UserBreak", breakItem.UserBreak);
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();

                writer.WriteEndObject();
            }
            writer.WriteEndArray();

            writer.WriteEndObject();
        }

        return sb.ToString();
    }

    private void WriteProperty(JsonWriter writer, string name, object value)
    {
        writer.WritePropertyName(name);

        if (value == null)
        {
            writer.WriteNull();
        }
        else
        {
            writer.WriteValue(value);
        }
    }

}

[Serializable]
public class AppointmentData
{
    public IEnumerable<ExternalEvent> ExteralEvents { get; set; }

    public IEnumerable<Appointment> Appointments { get; set; }

    public IEnumerable<Resource> Resources { get; set; }
}

[Serializable]
public class ClosedDay
{
    public int Year { get; set; }

    public int Month { get; set; }

    public int Day { get; set; }
}

[Serializable]
public class Appointment
{
    public long Id { get; set; }

    public long AppointmentId { get; set; }

    public int Year { get; set; }

    public int Month { get; set; }

    public int Day { get; set; }

    public int StartHour { get; set; }

    public int StartMinute { get; set; }

    public int EndHour { get; set; }

    public int EndMinute { get; set; }

    public long ResourceId { get; set; }

    public string Description { get; set; }

    public long Status { get; set; }

    public bool IsClass { get; set; }

    public int ProcessingLength { get; set; }


    public long ClientId { get; set; }

    public string ClientName { get; set; }

    public string ClientPhone { get; set; }

    public string ClientNotes { get; set; }

    public bool ClientHasMobile { get; set; }

    public bool ClassFull { get; set; }

    public string ClientWaiting { get; set; }

    public string PromotionCode { get; set; }

    public string ArrivalNote { get; set; }

    public string Labels { get; set; }

    public bool ReminderSent { get; set; }

    public bool Cancelled { get; set; }

    public IEnumerable<AppointmentItems> Items { get; set; }
}

[Serializable]
public class AppointmentItems
{
    public string Name { get; set; }

    public int Length { get; set; }

    public int ProcessingTime { get; set; }

    public string Resource { get; set; }
}

[Serializable]
public class OpenHours
{
    public int DayOfWeek { get; set; }

    public int? OpenHour { get; set; }

    public int? CloseHour { get; set; }
}

[Serializable]
public class Resource
{
    public Resource()
    {
        Breaks = new List<ResourceBreak>();
        Blocks = new List<ResourceBlock>();
        OpenCloseBreaks = new List<ResourceBreak>();
    }

    public long Id { get; set; }

    public string Name { get; set; }

    public int BlockLength { get; set; }

    public int StartHour { get; set; }

    public int EndHour { get; set; }

    public IEnumerable<ResourceBreak> Breaks { get; set; }

    public IEnumerable<ResourceBlock> Blocks { get; set; }

    public IEnumerable<ResourceBreak> OpenCloseBreaks { get; set; }

}

[Serializable]
public class ExternalEvent
{
    public long Id { get; set; }

    public int Year { get; set; }

    public int Month { get; set; }

    public int Day { get; set; }

    public int DayOfWeek { get; set; }

    public int StartHour { get; set; }

    public int StartMinute { get; set; }

    public int EndHour { get; set; }

    public int EndMinute { get; set; }

    public int Length { get; set; }

    public string Description { get; set; }
}

[Serializable]
public class ResourceBreak
{
    public int Year { get; set; }

    public int Month { get; set; }

    public int Day { get; set; }

    public int DayOfWeek { get; set; }

    public int StartHour { get; set; }

    public int StartMinute { get; set; }

    public int Length { get; set; }

    public string Description { get; set; }

    public bool OtherBreak { get; set; }

    public bool UserBreak { get; set; }
}

[Serializable]
public class ResourceBlock
{
    public int StartHour { get; set; }

    public int StartMinute { get; set; }

    public int Length { get; set; }
}

[Serializable]
public class Status
{
    public long Id { get; set; }

    public string Description { get; set; }

    public int Color { get; set; }
}

[Serializable]
public class LocationStaff
{
    public long Id { get; set; }

    public string Name { get; set; }
}
like image 644
Craig Avatar asked Apr 20 '14 14:04

Craig


People also ask

Is System text JSON faster than Newtonsoft?

As can be seen above, the System. Text. Json is much faster than the Newtonsoft. Json.

Is JSON serialization fast?

Json serializer, serializing objects to and from JSON in . NET is FAST! However, the actual performance you get depends a bit on how you use it. Using DotNetBenchmark, we take a look at some different patterns that can be used for serializing an object to and from a file on disk.

Is Newtonsoft JSON obsolete?

Newtonsoft. Json package is not provided by RestSharp, is marked as obsolete on NuGet, and no longer supported by its creator.

Is Newtonsoft JSON free for commercial use?

Json.NET is open source software and is completely free for commercial use.


1 Answers

You should give Jon Bellamy the points for the answer, but here is a little more detail:

I had the same problem with a project I'm working on and I solved it by following the advice on this page:

http://www.newtonsoft.com/json/help/html/Performance.htm

Specifically, they recommend manually serializing your objects when performance is critical:

public static string ToJson(this Person p)
{
    StringWriter sw = new StringWriter();
    JsonTextWriter writer = new JsonTextWriter(sw);

    // {
    writer.WriteStartObject();

    // "name" : "Jerry"
    writer.WritePropertyName("name");
    writer.WriteValue(p.Name);

    // "likes": ["Comedy", "Superman"]
    writer.WritePropertyName("likes");
    writer.WriteStartArray();
    foreach (string like in p.Likes)
    {
        writer.WriteValue(like);
    }
    writer.WriteEndArray();

    // }
    writer.WriteEndObject();

    return sw.ToString();
}

My example in VB looks like this:

    Public Function SerializeWords(ByRef oWords As List(Of Word))
        Dim sb As New StringBuilder
        Dim sw As New IO.StringWriter(sb)
        Using oWriter As Newtonsoft.Json.JsonWriter = New Newtonsoft.Json.JsonTextWriter(sw)
            With oWriter
                .WriteStartArray()
                For Each oWord As Word In oWords
                    .WriteStartObject()

                    .WritePropertyName("ID")
                    .WriteValue(oWord.ID)

                    .WritePropertyName("Phonics")
                    .WriteValue(oWord.Phonics)

                    .WritePropertyName("Word_")
                    .WriteValue(oWord.Word_)

                    .WritePropertyName("WordLength")
                    .WriteValue(oWord.WordLength)

                    .WriteEndObject()
                Next
                .WriteEndArray()

            End With
        End Using
        Return sb.ToString

    End Function

Notice how both functions are strongly typed. I believe when you use Newtonsoft.Json.JsonConvert.SerializeObject() it's using reflection to get the job done (which can really add up when you have many objects with many properties).

Anyways... once I wrote my own serializer, my time serializing a list of 250 "Word" objects went from 28 seconds using JsonConvert.SerializeObject() method to 31 milliseconds using my own function.

like image 102
Frog Pr1nce Avatar answered Sep 26 '22 03:09

Frog Pr1nce