Ошибка при сериализации с использованием 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(...)?
2 ответа
[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" };
}
- Получить данные из БД.
- Необходимо преобразовать ViewModel (List) в объект Telerik GridModel.
- Используйте JsonSerializer от Newton Soft, чтобы преобразовать GridModel в строку JSON (здесь нет ограничений по длине!) Telerik Grid должен знать общее количество записей, и по какой-то причине его не было в JSON. Обновите его с помощью метода Replace().
- Используйте объект ContentResult вместо ActionResult или JsonResult. При этом вы можете определить свою собственную полезную нагрузку данных.
Единственный недостаток этого точного решения - если оно наконец достигает 4 ГБ. В этот момент он, вероятно, приведет к сбою в большинстве браузеров, если у вас нет способа разделить возврат. Я бы добавил проверку на максимальную длину и выбросил бы ошибку.
В MVC 4 и 5 это должно быть легко исправлено с помощью параметра в файле веб-конфигурации.
У меня была такая же проблема в MVC3, и я просто исправил ее, заменив ValueProviderFactories в app_start, следуя этой теме: