4

I am using Entity Framework as my ORM. It has ComplexTypeAttribute (which is used to annotate POCO's). Properties that are complex types, are always instantiated (using default constructor), regardless of their value; And as a consequence, are always serialized by ServiceStack JsonSerializer (along with their properties).

JSON.NET has an enum called DefaultValueHandling, which can be used in these situations.

Does ServiceStack have something similar?

For example:

class Person
{
   string Name { get; set; }
   Address Address { get; set; }
}

[ComplexType]
class Address
{
   string Street { get; set; }
   int Number { get; set; }
   int PostalCode { get; set; }
}

When I serialize a person that doesn't have address I get this:

"{ Name: Jim, Address : { Number: 0, PostalCode: 0 } }" 

In Json.Net if I set DefaultValueHandling to Ignore, I only get

 "{ Name: Jim }"
Scott
  • 21,211
  • 8
  • 65
  • 72

2 Answers2

4

Yes, here are the different ways you can ignore properties with ServiceStack's JSON and Text serializers.

The serializers also support multiple hooks to customize serialization and deserialization.

The JsConfig class shows all the customizations that are possible.

Community
  • 1
  • 1
mythz
  • 141,670
  • 29
  • 246
  • 390
  • I don't want to ignore these properties. I want to serialize them if they have non default values. – Ivan Milutinović Feb 14 '13 at 23:02
  • All non-default public properties are serialized automatically. Also [you're headed for a world of hurt](http://www.infoq.com/articles/interview-servicestack) if you want to re-use EF ORM models as DTO's. Create explicit DTOs for the task and use ServiceStack's built-in `TFrom.TranslateTo()` or `To.PopulateFrom(from)` auto mappers. – mythz Feb 14 '13 at 23:12
  • Yes, but default complex properties are serialized, even tough they contain only default values, as in my example. – Ivan Milutinović Feb 15 '13 at 12:37
  • They'll only get serialized if they're non-null, i.e. as expected. We don't have a 'dont serialize if a class only has properties of default value', but we do have the custom serialization hooks I listed above that could help. – mythz Feb 15 '13 at 15:00
  • Well, I was thinking something like if(adressProperty == new Address()) ignore – Ivan Milutinović Feb 15 '13 at 23:48
  • So you're not testing on reference equality here (since it will always false for reference types), which means everyone would have to override and provide a custom implementation of `object.Equals()`. Unless you expected the serializer to provide a default impl by reflectively comparing every property against its default value. We don't support this type of magic behavior. – mythz Feb 16 '13 at 01:02
  • Yeah sorry, I meant equals. If you can edit your answer to say this behavior is not supported, I'll mark it as accepted. – Ivan Milutinović Feb 16 '13 at 11:09
  • And just to clarify. Serializer wouldn't need to recursively go trough every property, It would just need to do equals check with instance initialized with parameterless constructor. – Ivan Milutinović Feb 16 '13 at 11:16
  • 1
    ?? even with an empty instance it still have to go through every property to check 2 classes have the same shape/values. Also your question is misleading you're asking for a equality against a **new instance of a reference type, created with a parameterless constructor**, and not the default of a value type `default(T)` or a ref type (which is null). – mythz Feb 21 '13 at 05:27
  • Ok I wasn't clear. I used the word default value, because a setting in JSON.NET which does exactly this, is called DefaultValueHandling – Ivan Milutinović Feb 22 '13 at 21:31
1

Please consider changing your value types to nullable data types and set null as default value for any reference type.

class Person
{
   string Name { get; set; }
   Address Address { get; set; }
}

[ComplexType]
class Address
{
   string Street { get; set; }
   int? Number { get; set; }
   int? PostalCode { get; set; }
}

This should help you get rid of attributes with default values as ServiceStack Text will omit properties with null value. Also observe that 'Age' which is of type int? is omitted from serialized output when it is null. The example also demonstrates serialization using anonymous objects.

Example below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceStack;

namespace JsonTest
{
    class Person
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public int? Age { get; set; }
        public List<Person> Children { get; set; }

        public Person()
        {
            Children = new List<Person>();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var c1 = new Person { Name = "John", Address = "USA", Age = null };
            var c2 = new Person { Name = "John", Address = "USA", Age = 12 };
            List<Person> children = new List<Person>();
            children.Add(c1);
            string name = "Jim";
            // Uncomment lines below and check  - Children attribute is omitted from JSON result
            // children = null;
            // name = null;
            var p1 = new { Name = name, Address = "USA", Age=40, Children = children};
            var p2 = new Person { Name = "Jim", Address = "USA" , Age = null};
            p2.Children.Add(c2);
            Console.WriteLine(p1.ToJson());
            Console.WriteLine(p2.ToJson());
            Console.ReadLine();
        }
    }
}

Output:

{"Name":"Jim","Address":"USA","Age":40,"Children":[{"Name":"John","Address":"USA","Children":[]}]}
{"Name":"Jim","Address":"USA","Children":[{"Name":"John","Address":"USA","Age":12,"Children":[]}]}

{"Address":"USA","Age":40}
{"Name":"Jim","Address":"USA","Children":[{"Name":"John","Address":"USA","Age":12,"Children":[]}]}