Error during serialization using the JSON JavaScriptSerializer. Should be using the JSON.NET JsonSerializer

3.1k views Asked by At

I've added Newton Soft to the mix and am using this blog as a template: http://wingkaiwan.com/2012/12/28/replacing-mvc-javascriptserializer-with-json-net-jsonserializer/

I now have:

public class BaseJsonController : BaseController
{
    protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonNetResult
        {
            Data = data,
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            JsonRequestBehavior = behavior
        };
    }
}

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(this.Settings);

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

Now, in my controller I did this:

[HandleError]
public class ProcurementActionsController : BaseJsonController
{
    ...

    [GridAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult AjaxGetAll(string pageFilter = null, string searchTerm = null)
    {
        var rawData = GetProcurementActions(pageFilter);
        return new JsonNetResult 
        {
            Data = new GridModel { Data = rawData },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet,
            Settings = { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }
        };
    }

    ...

}

However, I am still getting the same error! According to the stack trace it is still trying to use the JavaScriptSerializer instead of the JsonSerializer:

[InvalidOperationException: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.]
   System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, StringBuilder output, SerializationFormat serializationFormat) +188
   System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj) +56
   System.Web.Mvc.JsonResult.ExecuteResult(ControllerContext context) +418
   System.Web.Mvc.<>c__DisplayClass14.<InvokeActionResultWithFilters>b__11() +31
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +656883
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +656883
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +254
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +658100
   System.Web.Mvc.Controller.ExecuteCore() +125
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +48
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +15
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +85
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +51
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +454
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +263

Is it because of the Async call? If so, what do I need to override in my BaseJsonController to get this to call the correct ExecuteResult(...) method?

2

There are 2 answers

0
Keith Barrows On BEST ANSWER
    [GridAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult AjaxGetAll(string pageFilter = null, string searchTerm = null)
    {
        var rawData = GetProcurementActions(pageFilter);
        var gridData = new GridModel { Data = rawData };
        var json = JsonConvert.SerializeObject(gridData).Replace("\"Total\":0,\"Aggregates\":null", String.Format("\"Total\":{0},\"Aggregates\":null", rawData.Count));

        return new ContentResult { Content = json, ContentType = "application/json" };
    }
  1. Get the data from the DB.
  2. Need to convert the ViewModel (List) into Telerik's GridModel object.
  3. Use Newton Soft's JsonSerializer to convert the GridModel to a JSON string (no length limits here!) The Telerik Grid needs to know the total records and for some reason it was not in the JSON. Update it via the Replace() method.
  4. Use the ContentResult object instead of the ActionResult or JsonResult. With this you can define your own data payload.

The only drawback to this exact solution is if it finally hits about 4GB. At that point it will probably crash most browsers unless you have a way chunk the return. I would add a check for max length and toss an error.

1
Lachezar Bozhkov On

In MVC 4 and 5 this should be fixed easily by parameter in the web config file.

I had the same problem in MVC3 and just fixed it by replacing ValueProviderFactories in the app_start, following this thread:

http://forums.asp.net/t/1751116.aspx