MaxJsonLength exception in ASP.NET MVC pendant JavaScriptSerializer

dans l'une de mes actions de contrôleur, je renvoie un très grand JsonResult pour remplir une grille.

je suis le suivant InvalidOperationException exception:

erreur lors de la sérialisation ou de la desérialisation en utilisant le JavaScriptSerializer JSON. La longueur de la chaîne dépasse la valeur définie sur la propriété maxJsonLength.

fixant la propriété maxJsonLength dans le web.config à un plus haut la valeur ne montre malheureusement aucun effet.

<system.web.extensions>
  <scripting>
    <webServices>
      <jsonSerialization maxJsonLength="2147483644"/>
    </webServices>
  </scripting>
</system.web.extensions>

Je ne veux pas le renvoyer comme une chaîne comme mentionné dans ce alors répondez.

dans ma recherche, je suis tombé sur ce post de blog où l'écriture d'un propre ActionResult (par exemple LargeJsonResult : JsonResult ) est recommandé pour contourner ce comportement.

Est-ce la seule solution?

Est - ce un bug dans ASP.NET MVC?

Ai-je raté quelque chose?

Toute aide serait appréciée.

103
demandé sur Community 2011-04-17 13:56:53

11 réponses

il semble que cela ait été fixé dans MVC4.

vous pouvez faire ceci, qui a bien fonctionné pour moi:

public ActionResult SomeControllerAction()
{
  var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet);
  jsonResult.MaxJsonLength = int.MaxValue;
  return jsonResult;
}
185
répondu Orion Edwards 2012-12-19 20:57:11

vous pouvez aussi utiliser ContentResult comme suggéré ici au lieu de sousclasser JsonResult .

var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };

return new ContentResult()
{
    Content = serializer.Serialize(data),
    ContentType = "application/json",
};
31
répondu SliverNinja - MSFT 2013-05-08 21:03:44

malheureusement le web.le paramètre de configuration est ignoré par l'implémentation par défaut JsonResult . Donc je suppose que vous aurez besoin d'implémenter un résultat JSON personnalisé pour surmonter ce problème.

24
répondu Darin Dimitrov 2011-04-17 13:56:28

pas besoin de classe personnalisée. C'est tout ce qui est nécessaire:

return new JsonResult { Data = Result, MaxJsonLength = Int32.MaxValue };

Result est cette donnée que vous souhaitez sérialiser.

18
répondu John 2013-04-08 02:21:56

si utiliser Json.NET pour générer la chaîne de caractères json , il n'est pas nécessaire de définir la valeur MaxJsonLength .

return new ContentResult()
{
    Content = Newtonsoft.Json.JsonConvert.SerializeObject(data),
    ContentType = "application/json",
};
5
répondu AechoLiu 2015-02-06 06:29:52

j'ai résolu le problème en suivant cette lien

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());
    }
4
répondu Sajjad Ali Khan 2016-06-15 23:40:30

vous pouvez essayer de définir dans votre expression LINQ seulement le champ dont vous aurez besoin.

exemple. Imaginez que vous ayez un modèle avec Id, Nom, téléphone et image (byte array) et que vous ayez besoin de charger à partir de json dans une liste de sélection.

LINQ Query:

var listItems = (from u in Users where u.name.Contains(term) select u).ToList();

le problème ici est " sélectionnez u " qui obtiennent tous les champs. Donc, si vous avez de grandes photos, booomm.

comment résoudre? très, très simple.

var listItems = (from u in Users where u.name.Contains(term) select new {u.Id, u.Name}).ToList();

les meilleures pratiques sont sélectionnez seulement le domaine que vous allez utiliser.

rappelez-vous. C'est un conseil simple, mais peut aider beaucoup ASP.NET MVC developpers.

2
répondu glanes 2014-09-24 01:18:25

Alternative ASP.NET fixation MVC 5:

dans mon cas, l'erreur s'est produite pendant la demande. La meilleure approche dans mon scénario est de modifier le JsonValueProviderFactory qui applique le correctif au projet global et peut être fait en éditant le fichier global.cs comme tel.

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

ajouter un web.entrée de configuration:

<add key="aspnet:MaxJsonLength" value="20971520" />

et ensuite créer les deux classes suivantes

public class JsonValueProviderConfig
{
    public static void Config(ValueProviderFactoryCollection factories)
    {
        var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single();
        factories.Remove(jsonProviderFactory);
        factories.Add(new CustomJsonValueProviderFactory());
    }
}

il s'agit essentiellement d'une copie exacte de l'implémentation par défaut trouvée dans System.Web.Mvc mais avec l'ajout d'un web configurable.config appsetting valeur aspnet: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;
    }
}
1
répondu Maxim Gershkovich 2018-06-03 11:10:15

vous devez lire la section configuration manuellement avant que votre code renvoie un objet JsonResult. Il suffit de lire à partir du web.config en ligne simple:

        var jsonResult = Json(resultsForAjaxUI);
        jsonResult.MaxJsonLength = (ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as System.Web.Configuration.ScriptingJsonSerializationSection).MaxJsonLength;
        return jsonResult;

assurez-vous que vous avez défini l'élément de configuration dans web.config

0
répondu Pavel Nazarov 2017-08-15 11:28:06

rien de ce qui précède n'a fonctionné pour moi jusqu'à ce que je change l'Action en [HttpPost] . et a fait le type ajax comme 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);
            ..
            ..
            ...

    }

et l'appel ajax comme

$.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...");
    }
});
0
répondu jAntoni 2018-07-04 12:17:26

cela a fonctionné pour moi

        JsonSerializerSettings json = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        var result = JsonConvert.SerializeObject(list, Formatting.Indented, json);
        return new JsonResult { Data = result, MaxJsonLength = int.MaxValue };
0
répondu Steven Hernández 2018-08-21 14:38:58