2

I've overwritten the default Json Serializer from ASP.NET MVC with:

public class JsonNetResult : JsonResult
{
    public JsonNetResult()
    {
        Settings = new JsonSerializerSettings
                       {
                           ReferenceLoopHandling = ReferenceLoopHandling.Error,
                       };
    }

    public JsonSerializerSettings Settings { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            throw new InvalidOperationException("JSON GET is not allowed");

        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;

        if (this.ContentEncoding != null)
            response.ContentEncoding = this.ContentEncoding;
        if (this.Data == null)
            return;

        var scriptSerializer = JsonSerializer.Create();

        using (var sw = new StringWriter())
        {
            scriptSerializer.Serialize(sw, this.Data);
            response.Write(sw.ToString());
        }
    }
}

And when I am Serializing the Following:

public JsonResult GetLevels()
    {
        List<ListItem> items = new List<ListItem>();
        items.Add(new ListItem() { Text = "Home", Value = "5"});
        items.Add(new ListItem() { Text = "Live", Value = "6"});
        items.Add(new ListItem() { Text = "Dev", Value = "7"});
        items.Add(new ListItem() { Text = "Staging", Value = "8"});

        return Json(items, JsonRequestBehavior.AllowGet);
    }

The JavaScript Object I get is the following:

Levels: Array[4] 0: "Home" 1: "Live" 2: "Dev" 3: "Staging"

So here all my Informations are lost like value and so on. But when I use the Default Json serializer then I got the "right" Informations serialized

Levels: Array[4]

0: Object Attributes: Object Enabled: true Selected: false Text: "Home" Value: "5"

1: Object Attributes: Object Enabled: true Selected: false Text: "Live" Value: "6" ...

but I need to use the custom serializer because of the DateTime serialization. But I don't know what I am doing wrong with the custom JsonNetResult or what I am missing. Because it can't be normal that here is Data missing or?

tereško
  • 58,060
  • 25
  • 98
  • 150
squadwuschel
  • 3,328
  • 3
  • 34
  • 45

1 Answers1

3

This problem happens because the ListItem class has a [TypeConverter] attribute applied to it. When Json.Net sees this, it uses the associated TypeConverter to get the value instead of serializing it as a normal object. In this case the TypeConverter converts the ListItem to a simple string, so that is why you do not get the full serialization you are expecting. The JavaScriptSerializer (the default serializer used by MVC) does not do this check, so the ListItem serializes normally in that case.

You can use a custom ContractResolver to tell Json.Net to serialize ListItem as an object instead of using a TypeConverter. Here is the code you would need:

class CustomContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (objectType == typeof(ListItem))
            return base.CreateObjectContract(objectType);

        return base.CreateContract(objectType);
    }
}

Add the resolver to your JsonSerializerSettings and you should be ready to go:

Settings = new JsonSerializerSettings
{
    ContractResolver = new CustomContractResolver(),
    ...        
};

Note: be sure that when you create the JsonSerializer that you pass the settings to it-- in your code it looks like you are not doing this.

var scriptSerializer = JsonSerializer.Create(Settings);
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300