Исключение MaxJsonLength в ASP.NET MVC во время JavaScriptSerializer
в одном из моих действий контроллера я возвращаюсь очень большая JsonResult
для заполнения сетки.
Я получаю следующее InvalidOperationException
исключения:
ошибка при сериализации или десериализации с помощью JSON JavaScriptSerializer. Длина строки превышает значение, установленное для свойства maxJsonLength.
задание maxJsonLength
собственность в web.config
к более высокому значению, к сожалению, не показывает никаких эффект.
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644"/>
</webServices>
</scripting>
</system.web.extensions>
Я не хочу передавать его обратно в виде строки, как указано в этом ответе SO.
в своих исследованиях я наткнулся этой сообщение в блоге, где пишется собственный ActionResult
(например,LargeJsonResult : JsonResult
) рекомендуется обойти это поведение.
это тогда единственное решение?
Это ошибка в ASP.NET MVC?
Я что-то упустил?
любая помощь была бы очень признательна.
11 ответов:
похоже, это было исправлено в MVC4.
вы можете сделать это, что хорошо работало для меня:
public ActionResult SomeControllerAction() { var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet); jsonResult.MaxJsonLength = int.MaxValue; return jsonResult; }
вы также можете использовать
ContentResult
как предложенные здесь вместо подклассыJsonResult
.var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 }; return new ContentResult() { Content = serializer.Serialize(data), ContentType = "application/json", };
к сожалению, в интернете.настройка конфигурации - игнорируется реализацией JsonResult по умолчанию. Поэтому я думаю, вам нужно будет реализовать пользовательский результат json, чтобы преодолеть эту проблему.
нет необходимости в пользовательском классе. Это все, что нужно:
return new JsonResult { Data = Result, MaxJsonLength = Int32.MaxValue };
здесь
Result
Это данные, которые вы хотите сериализовать.
Если использовать Json.NET для генерации
json
строка, не нужно устанавливатьMaxJsonLength
значение.return new ContentResult() { Content = Newtonsoft.Json.JsonConvert.SerializeObject(data), ContentType = "application/json", };
Я решил проблему, следуя этомуссылке
namespace System.Web.Mvc { public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { if (controllerContext == null) throw new ArgumentNullException("controllerContext"); if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) return null; var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream); var bodyText = reader.ReadToEnd(); return String.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>(JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter()), CultureInfo.CurrentCulture); } } } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); //Remove and JsonValueProviderFactory and add JsonDotNetValueProviderFactory ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault()); ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory()); }
вы можете попробовать определить в своем выражении LINQ только то поле, которое вам понадобится.
пример. Представьте, что у вас есть модель с идентификатором, именем, телефоном и изображение (байтовый массив) и нужно загрузить из json в список выбора.
запрос LINQ:
var listItems = (from u in Users where u.name.Contains(term) select u).ToList();
проблема здесь-это " выберите u " это получить все поля. Так что, если у вас есть большие фотографии, booomm.
Как решить? очень-очень простой.
var listItems = (from u in Users where u.name.Contains(term) select new {u.Id, u.Name}).ToList();
рекомендуется выбрать только то поле, которое вы будете использовать.
помню. Это простой совет, но может помочь многим ASP.NET разработчики MVC.
альтернатива ASP.NET MVC 5 исправить:
в моем случае ошибка произошла во время запроса. Лучший подход в моем сценарии-это изменение фактического
JsonValueProviderFactory
который применяет исправление к глобальному проекту и может быть выполнен путем редактированияglobal.cs
файл как таковой.JsonValueProviderConfig.Config(ValueProviderFactories.Factories);
добавить веб -.запись config:
<add key="aspnet:MaxJsonLength" value="20971520" />
а затем создать два следующих класса
public class JsonValueProviderConfig { public static void Config(ValueProviderFactoryCollection factories) { var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single(); factories.Remove(jsonProviderFactory); factories.Add(new CustomJsonValueProviderFactory()); } }
это в основном точная копия по умолчанию реализация найдена в
System.Web.Mvc
но с добавлением конфигурируемой сети.config appsetting valueaspnet:MaxJsonLength
.public class CustomJsonValueProviderFactory : ValueProviderFactory { /// <summary>Returns a JSON value-provider object for the specified controller context.</summary> /// <returns>A JSON value-provider object for the specified controller context.</returns> /// <param name="controllerContext">The controller context.</param> public override IValueProvider GetValueProvider(ControllerContext controllerContext) { if (controllerContext == null) throw new ArgumentNullException("controllerContext"); object deserializedObject = CustomJsonValueProviderFactory.GetDeserializedObject(controllerContext); if (deserializedObject == null) return null; Dictionary<string, object> strs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); CustomJsonValueProviderFactory.AddToBackingStore(new CustomJsonValueProviderFactory.EntryLimitedDictionary(strs), string.Empty, deserializedObject); return new DictionaryValueProvider<object>(strs, CultureInfo.CurrentCulture); } private static object GetDeserializedObject(ControllerContext controllerContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) return null; string fullStreamString = (new StreamReader(controllerContext.HttpContext.Request.InputStream)).ReadToEnd(); if (string.IsNullOrEmpty(fullStreamString)) return null; var serializer = new JavaScriptSerializer() { MaxJsonLength = CustomJsonValueProviderFactory.GetMaxJsonLength() }; return serializer.DeserializeObject(fullStreamString); } private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value) { IDictionary<string, object> strs = value as IDictionary<string, object>; if (strs != null) { foreach (KeyValuePair<string, object> keyValuePair in strs) CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value); return; } IList lists = value as IList; if (lists == null) { backingStore.Add(prefix, value); return; } for (int i = 0; i < lists.Count; i++) { CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakeArrayKey(prefix, i), lists[i]); } } private class EntryLimitedDictionary { private static int _maximumDepth; private readonly IDictionary<string, object> _innerDictionary; private int _itemCount; static EntryLimitedDictionary() { _maximumDepth = CustomJsonValueProviderFactory.GetMaximumDepth(); } public EntryLimitedDictionary(IDictionary<string, object> innerDictionary) { this._innerDictionary = innerDictionary; } public void Add(string key, object value) { int num = this._itemCount + 1; this._itemCount = num; if (num > _maximumDepth) { throw new InvalidOperationException("The length of the string exceeds the value set on the maxJsonLength property."); } this._innerDictionary.Add(key, value); } } private static string MakeArrayKey(string prefix, int index) { return string.Concat(prefix, "[", index.ToString(CultureInfo.InvariantCulture), "]"); } private static string MakePropertyKey(string prefix, string propertyName) { if (string.IsNullOrEmpty(prefix)) { return propertyName; } return string.Concat(prefix, ".", propertyName); } private static int GetMaximumDepth() { int num; NameValueCollection appSettings = ConfigurationManager.AppSettings; if (appSettings != null) { string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers"); if (values != null && values.Length != 0 && int.TryParse(values[0], out num)) { return num; } } return 1000; } private static int GetMaxJsonLength() { int num; NameValueCollection appSettings = ConfigurationManager.AppSettings; if (appSettings != null) { string[] values = appSettings.GetValues("aspnet:MaxJsonLength"); if (values != null && values.Length != 0 && int.TryParse(values[0], out num)) { return num; } } return 1000; } }
вы должны прочитать из раздела конфигурации вручную, прежде чем ваш код возвращает объект JsonResult. Просто прочитайте из интернета.конфигурация в одной строке:
var jsonResult = Json(resultsForAjaxUI); jsonResult.MaxJsonLength = (ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as System.Web.Configuration.ScriptingJsonSerializationSection).MaxJsonLength; return jsonResult;
убедитесь, что вы определили элемент конфигурации в web.конфигурации
ничего из вышеперечисленного не сработало для меня, пока я не изменил действие как
[HttpPost]
. и сделал тип ajax какPOST
.[HttpPost] public JsonResult GetSelectedSignalData(string signal1,...) { JsonResult result = new JsonResult(); var signalData = GetTheData(); try { var serializer = new System.Web.Script.Serialization.JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 }; result.Data = serializer.Serialize(signalData); return Json(result, JsonRequestBehavior.AllowGet); .. .. ... }
и вызов ajax как
$.ajax({ type: "POST", url: some_url, data: JSON.stringify({ signal1: signal1,.. }), contentType: "application/json; charset=utf-8", success: function (data) { if (data !== null) { setValue(); } }, failure: function (data) { $('#errMessage').text("Error..."); }, error: function (data) { $('#errMessage').text("Error..."); } });