Ошибка во время сериализации с использованием JSON JavaScriptSerializer. Следует использовать JSON.NET JsonSerializer

Я добавил в список Newton Soft и использую этот блог в качестве шаблона: http://wingkaiwan.com/2012/12/28/replacing-mvc-javascriptserializer-with-json-net-jsonserializer./

Теперь у меня есть:

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());
        }
    }
}

Теперь в моем контроллере я сделал это:

[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 }
        };
    }

    ...

}

Тем не менее, я все еще получаю ту же ошибку! Судя по трассировке стека, он все еще пытается использовать JavaScriptSerializer вместо 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

Это из-за асинхронного вызова? Если да, то что мне нужно переопределить в моем BaseJsonController, чтобы заставить его вызывать правильный метод ExecuteResult(...)?


person Keith Barrows    schedule 03.12.2013    source источник


Ответы (2)


В MVC 4 и 5 это легко исправить с помощью параметра в файле веб-конфигурации.

У меня была такая же проблема в MVC3, и я просто исправил ее, заменив ValueProviderFactories в app_start, следуя этому потоку:

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

person Lachezar Bozhkov    schedule 04.12.2013
comment
Я добавил этот код в нашу кодовую базу. Однако это для входящего JSON, и я пытаюсь решить для исходящего JSON. Я нашел другой способ сделать это (см. мой ответ ниже)... - person Keith Barrows; 11.12.2013

    [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. Получить данные из БД.
  2. Необходимо преобразовать ViewModel (List) в объект Telerik GridModel.
  3. Используйте JsonSerializer от Newton Soft для преобразования GridModel в строку JSON (здесь нет ограничений по длине!) Telerik Grid должен знать общее количество записей, и по какой-то причине этого не было в JSON. Обновите его с помощью метода Replace().
  4. Используйте объект ContentResult вместо ActionResult или JsonResult. При этом вы можете определить свою собственную полезную нагрузку данных.

Единственным недостатком этого точного решения является то, что оно, наконец, достигает около 4 ГБ. В этот момент он, вероятно, приведет к сбою большинства браузеров, если у вас нет способа вернуть возврат. Я бы добавил проверку на максимальную длину и выбросил ошибку.

person Keith Barrows    schedule 05.12.2013