Eccezione MaxJsonLength in ASP.NET MVC durante JavaScriptSerializer


122

In una delle mie azioni del controller sto restituendo un'immagine molto grande JsonResultper riempire una griglia.

Ricevo la seguente InvalidOperationExceptioneccezione:

Errore durante la serializzazione o la deserializzazione utilizzando JSON JavaScriptSerializer. La lunghezza della stringa supera il valore impostato nella proprietà maxJsonLength.

L'impostazione della maxJsonLengthproprietà in web.configun valore più alto purtroppo non mostra alcun effetto.

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

Non voglio restituirlo come stringa come menzionato in questa risposta SO.

Nella mia ricerca mi sono imbattuto in questo post del blog in cui si consiglia di scrivere un proprio ActionResult(ad esempio LargeJsonResult : JsonResult) per aggirare questo comportamento.

Questa è quindi l'unica soluzione?
È un bug in ASP.NET MVC?
Mi sto perdendo qualcosa?

Qualsiasi aiuto sarebbe molto apprezzato.


2
Le tue soluzioni funzionano su MVC 3.
MatteoSp

1
@Matteo Sei sicuro? Questa è una vecchia domanda e non ricordo, ma a quanto pare l'ho etichettata come MVC3. Sfortunatamente non riesco a vedere la versione / data in cui è stato risolto / chiuso: aspnet.codeplex.com/workitem/3436
Martin Buberl

1
Certo, sto lavorando con MVC 3 e funziona. E fortunatamente, perché in MVC 3 non hai le proprietà "MaxJsonLength" citate nella risposta accettata.
MatteoSp

Risposte:


228

Sembra che questo sia stato risolto in MVC4.

Puoi farlo, che ha funzionato bene per me:

public ActionResult SomeControllerAction()
{
  var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet);
  jsonResult.MaxJsonLength = int.MaxValue;
  return jsonResult;
}

Sto impostando una stringa json in una proprietà ViewBag.MyJsonString ma ricevo lo stesso errore nella mia vista in fase di esecuzione sulla seguente riga javascript: var myJsonObj = @ Html.Raw (Json.Encode (ViewBag.MyJsonString));
Faisal Mq

1
Hey @orionedvards, @ GG, @ MartinBuberl Sto affrontando lo stesso problema di maxJson ma quando invio i dati al controller, come posso gestirlo, ho passato così tanto tempo a cercare su questo. Qualsiasi aiuto sarebbe grato.
katmanco

Nel mio caso non ha funzionato perché ho dovuto impostare MaxJsonLength prima che json serializzasse la raccolta.
César León

Nel mio caso funziona bene, ho dovuto implementarlo a causa di "IMMAGINI" in databile da presentare per l'utente finale. Senza di esso, blocca semplicemente senza alcun messaggio comprensibile.
Mauro Candido

33

Puoi anche usare ContentResultcome suggerito qui invece di sottoclassi JsonResult.

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

return new ContentResult()
{
    Content = serializer.Serialize(data),
    ContentType = "application/json",
};

2
nel mio caso, lavorando su un'app usa e getta, questa soluzione ha funzionato meglio per me. salvato l'implementazione di jsonresult. Grazie!
Christo


22

Non c'è bisogno di una classe personalizzata. Questo è tutto ciò che serve:

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

dove Resultsono i dati che desideri serializzare.


Errore 137 "System.Web.Mvc.JsonResult" non contiene una definizione per "MaxJsonLength"
PUG

Questo ha funzionato per me, tuttavia era ancora necessario aggiungere: JsonRequestBehavior = JsonRequestBehavior.AllowGet
DubMan

5

Se si utilizza Json.NET per generare la jsonstringa, non è necessario impostare il MaxJsonLengthvalore.

return new ContentResult()
{
    Content = Newtonsoft.Json.JsonConvert.SerializeObject(data),
    ContentType = "application/json",
};

4

Ho risolto il problema seguendo questo link

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

3

Sono sorpreso che nessuno abbia suggerito di utilizzare un filtro dei risultati. Questo è il modo più pulito per agganciarsi globalmente alla pipeline di azioni / risultati:

public class JsonResultFilter : IResultFilter
{
    public int? MaxJsonLength { get; set; }

    public int? RecursionLimit { get; set; }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (filterContext.Result is JsonResult jsonResult)
        {
            // override properties only if they're not set
            jsonResult.MaxJsonLength = jsonResult.MaxJsonLength ?? MaxJsonLength;
            jsonResult.RecursionLimit = jsonResult.RecursionLimit ?? RecursionLimit;
        }
    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
    }
}

Quindi, registra un'istanza di quella classe utilizzando GlobalFilters.Filters:

GlobalFilters.Filters.Add(new JsonResultFilter { MaxJsonLength = int.MaxValue });

2

Puoi provare a definire nella tua espressione LINQ solo i campi di cui avrai bisogno.

Esempio. Immagina di avere un modello con ID, nome, telefono e immagine (array di byte) e di dover caricare da json in un elenco di selezione.

Query LINQ:

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

Il problema qui è " seleziona u " che ottiene tutti i campi. Quindi, se hai foto grandi, booomm.

Come risolvere? molto, molto semplice.

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

La migliore pratica è selezionare solo il campo che utilizzerai.

Ricorda. Questo è un semplice suggerimento, ma può aiutare molti sviluppatori ASP.NET MVC.


1
Non presumo che l'utente in questo caso voglia filtrare i propri dati. Alcune persone hanno i requisiti per ripristinare una grande quantità di righe dal database ...
Simon Nicholls

2

Correzione alternativa ASP.NET MVC 5:

Nel mio caso l'errore si è verificato durante la richiesta. L'approccio migliore nel mio scenario è modificare l'attuale JsonValueProviderFactoryche applica la correzione al progetto globale e può essere fatto modificando il global.csfile come tale.

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

aggiungi una voce web.config:

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

e quindi creare le due classi seguenti

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

Questa è fondamentalmente una copia esatta dell'implementazione predefinita che si trova in, System.Web.Mvcma con l'aggiunta di un valore configurabile di configurazione app web.config 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;
    }
}

Grazie mille !
larizzatg

1

Nessuno dei precedenti ha funzionato per me fino a quando non ho cambiato l'azione come [HttpPost]. e ha reso il tipo ajax come 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);
            ..
            ..
            ...

    }

E l'ajax chiama come

$.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...");
    }
});

1
    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonResult()
        {
            Data = data,
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            JsonRequestBehavior = behavior,
            MaxJsonLength = Int32.MaxValue
        };
    }

È stata la soluzione per me in MVC 4.


0

È necessario leggere manualmente dalla sezione di configurazione prima che il codice restituisca un oggetto JsonResult. Leggi semplicemente da web.config in una sola riga:

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

Assicurati di aver definito l'elemento di configurazione in web.config


0

questo ha funzionato per me

        JsonSerializerSettings json = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        var result = JsonConvert.SerializeObject(list, Formatting.Indented, json);
        return new JsonResult { Data = result, MaxJsonLength = int.MaxValue };

0

c'è un altro caso: i dati vengono inviati dal client al server. quando si utilizza il metodo del controller e il modello è enorme:

    [HttpPost]
    public ActionResult AddOrUpdateConsumerFile(FileMetaDataModelView inputModel)
    {
        if (inputModel == null) return null;
     ....
    }

il sistema genera un'eccezione come questa "Errore durante la serializzazione o deserializzazione utilizzando JavaScriptSerializer JSON. La lunghezza della stringa supera il valore impostato nella proprietà maxJsonLength. Nome parametro: input"

Solo la modifica delle impostazioni di Web.config non è sufficiente per aiutare in questo caso. È inoltre possibile eseguire l'override del serializzatore json mvc per supportare dimensioni di modelli di dati enormi o deserializzare manualmente il modello da Request. Il metodo del controller diventa:

   [HttpPost]
    public ActionResult AddOrUpdateConsumerFile()
    {
        FileMetaDataModelView inputModel = RequestManager.GetModelFromJsonRequest<FileMetaDataModelView>(HttpContext.Request);
        if (inputModel == null) return null;
        ......
    }

   public static T GetModelFromJsonRequest<T>(HttpRequestBase request)
    {
        string result = "";
        using (Stream req = request.InputStream)
        {
            req.Seek(0, System.IO.SeekOrigin.Begin);
            result = new StreamReader(req).ReadToEnd();
        }
        return JsonConvert.DeserializeObject<T>(result);
    }

0

Puoi inserire questo codice in cshtml se stai restituendo la visualizzazione dal controller e desideri aumentare la lunghezza dei dati del sacchetto di visualizzazione durante la codifica in json in cshtml

@{
    var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
    jss.MaxJsonLength = Int32.MaxValue;
    var userInfoJson = jss.Serialize(ViewBag.ActionObj);
}

var dataJsonOnActionGrid1 = @Html.Raw(userInfoJson);

Adesso, dataJsonOnActionGrid1 sarà accessibile sulla pagina js e otterrai il risultato corretto.

Grazie

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.