12
namespace Booking.Areas.Golfy.Models
{
    public class Time
    {
        public string   time            { get; set; }
        public int      holes           { get; set; }
        public int      slots_available { get; set; }
        public decimal? price           { get; set; }
        public int?     Nextcourseid    { get; set; }

        public bool ShouldSerializeNextcourseid
        {
            get
            {
                return this.Nextcourseid != null;
            }
        }

        public bool? allow_extra { get; set; }

        public bool ShouldSerializeallow_extra
        {
            get
            {
                return this.allow_extra != null;
            }
        }
    }
}


namespace Booking.Areas.Golfy.Controllers
{
    public class TeetimesController : Controller
    {
        //
        // GET: /Golfy/Teetimes/
        public ActionResult Index(
            string date,
            int?   courseid = null,
            int?   clubid = null,
            int?   holes = null,
            int?   available = null,
            int?   prices = null
        )
        {
            var DateFrom = DateTime.ParseExact(date, "yyyy-MM-dd", CultureInfo.InvariantCulture);

            Teetimes r = BookingManager.GetBookings(new Code.Classes.Params.ParamGetBooking()
            {
                ClubID = clubid
                , DateFrom = DateFrom
                , DateTo = DateFrom.AddDays(1)
                , GroundID = courseid
            });

            return Json(r, JsonRequestBehavior.AllowGet);
        }
    }
}

The webservice above returns a json string with several intance of Time.

I'd like properties Nextcourseid and allow_extra to be left out of the output when their values are null.

I tried ShouldSerializeXxx but it doesn't seems to work.
FYI: I also tried [ScriptIgnore] which work but isn't conditional.

3 Answers 3

14

You can't use the default Json ActionResult to remove null properties.

You can take a look at JSON.NET, it has an attribute that you can set to remove the property if it is null

[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]

Or if you don't want to use other libraries you can create your own json custom ActionResult and register a new converter for the default JavaScriptSerializer, like this:

public class JsonWithoutNullPropertiesResult : ActionResult
{
    private object Data { get; set; }

    public JsonWithoutNullPropertiesResult(object data)
    {
        Data = data;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = "application/x-javascript";
        response.ContentEncoding = Encoding.UTF8;

        if (Data != null)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new[] { new NullPropertiesConverter() });
            string ser = serializer.Serialize(Data);
            response.Write(ser);
        }
    }
}

public class NullPropertiesConverter : JavaScriptConverter
{
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var toSerialize = new Dictionary<string, object>();

        foreach (var prop in obj.GetType()
                                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                .Select(p => new
                                {
                                    Name = p.Name,
                                    Value = p.GetValue(obj)
                                })
                                .Where(p => p.Value != null))
        {
            toSerialize.Add(prop.Name, prop.Value);
        }

        return toSerialize;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return GetType().Assembly.GetTypes(); }
    }
}

And now in your view:

public ActionResult Index()
{
    Teetimes r = BookingManager.GetBookings();
    return new JsonWithoutNullPropertiesResult(t);
}
Sign up to request clarification or add additional context in comments.

Comments

2

I always had problems with framework-embedded json serializer, therefore I use Json.NET. Here's little example testing these two serializers:

public class Model {
    public int Id { get; set; }
    public string Name { get; set; }

    public bool ShouldSerializeName() {
        return Name != null;
    }
}

class Program {
    static void Main(string[] args) {
        var t1 = new Model {
            Name = "apw8u3rdmapw3urdm",
            Id = 298384
        };
        var t2 = new Model {
            Id = 234235
        };

        Test(t1);
        Test(t2);
    }

    static void Test(Model model) {
        Console.WriteLine("JSon from .Net: {0}", ToJson(model));
        Console.WriteLine("JSon from JSon.Net: {0}", ToDotNetJson(model));
    }

    static string ToJson(Model model) {
        var s = new JavaScriptSerializer();
        return s.Serialize(model);
    }

    static string ToDotNetJson(Model model) {
        return JsonConvert.SerializeObject(model);
    }
}

You have to include System.Web.Extensions as dependency and install Json.Net with nuget to have the example working.

Here's some documentation form Json.NET and Framework-embedded serializer

Comments

2

The answers given are interresting, but I had started using DataContractJsonSerializer in the meantime.
And it does the job fine without the need of using a third party framework (though JSON.Net does seem like widely used).

public ActionResult Index(
    string date
    , int? courseid = null
    , int? clubid = null
    , int? holes = null
    , int? available = null
    , int? prices = null
)
{
    var DateFrom = DateTime.ParseExact(date, "yyyy-MM-dd", CultureInfo.InvariantCulture);

    MTeetimes r = BookingManager.GetBookings(new Code.Classes.Params.ParamGetBooking()
    {
        ClubID = clubid
        , DateFrom = DateFrom
        , DateTo = DateFrom.AddDays(1)
        , GroundID = courseid
    });

    // return Json(r, JsonRequestBehavior.AllowGet);

    string response;
    var serializer = new DataContractJsonSerializer(typeof(MTeetimes));

    // Serialize
    using (var ms = new MemoryStream())
    {
        serializer.WriteObject(ms, r);
        response = Encoding.Default.GetString(ms.ToArray());
    }

    return Content(response);
}


[DataContract]
public class Time
{
    [DataMember(Name="time", EmitDefaultValue = false)]
    public string Time
    {
        get;
        set;
    }

    [DataMember(Name = "holes", EmitDefaultValue = false)]
    public int Holes
    {
        get;
        set;
    }

    [DataMember(Name = "slots_available", EmitDefaultValue = false)]
    public int Slots_available
    {
        get;
        set;
    }

    [DataMember(Name = "price", EmitDefaultValue = false)]
    public decimal? Price
    {
        get;
        set;
    }

    [DataMember(Name = "nextcourseid", EmitDefaultValue = false)]
    public int? Nextcourseid
    {
        get;
        set;
    }

    [DataMember(Name = "allow_extra", EmitDefaultValue = false)]
    public bool? Allow_extra
    {
        get;
        set;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.