JavaScriptSerializer sırasında ASP.NET MVC'de MaxJsonLength istisnası


122

Denetleyici eylemlerimden birinde, JsonResultbir ızgarayı doldurmak için çok büyük bir değer döndürüyorum .

Aşağıdaki InvalidOperationExceptionistisnayı alıyorum :

JSON JavaScriptSerializer kullanılarak serileştirme veya seriyi kaldırma sırasında hata. Dizenin uzunluğu maxJsonLength özelliğinde ayarlanan değeri aşıyor.

maxJsonLengthMülkün web.configdaha yüksek bir değere ayarlanması maalesef herhangi bir etki göstermez.

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

Bu SO cevabında belirtildiği gibi onu bir dize olarak geri geçirmek istemiyorum .

Araştırmamda , bu davranışı atlatmak için kendi yazmanın (örneğin ) önerildiği bu blog gönderisine rastladım .ActionResultLargeJsonResult : JsonResult

O zaman tek çözüm bu mu?
Bu ASP.NET MVC'de bir hata mı?
Bir şey mi kaçırıyorum?

Herhangi bir yardım çok takdir edilecektir.


2
Çözümleriniz MVC 3 üzerinde çalışıyor
MatteoSp

1
@Matteo Emin misin? Bu eski bir soru ve hatırlayamıyorum ama görünüşe göre onu MVC3 olarak etiketledim. Ne yazık ki sabit var versiyon / tarih göremiyorum / kapalı: aspnet.codeplex.com/workitem/3436
Martin Buberl

1
Elbette, MVC 3 ile çalışıyorum ve işe yarıyor. Ve neyse ki, MVC 3'te kabul edilen yanıtta belirtilen "MaxJsonLength" özelliklerine sahip değilsiniz.
MatteoSp

Yanıtlar:


228

Görünüşe göre bu, MVC4'te düzeltilmiş.

Benim için iyi çalışan bunu yapabilirsiniz:

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

ViewBag.MyJsonString özelliğine bir json dizesi ayarlıyorum, ancak aşağıdaki javascript satırındaki çalışma zamanında görünümümde aynı hatayı alıyorum: var myJsonObj = @ Html.Raw (Json.Encode (ViewBag.MyJsonString));
Faisal Mq

1
Hey @orionedvards, @ GG, @ MartinBuberl Aynı maxJson sorunuyla karşı karşıyayım, ancak denetleyiciye veri gönderirken, bunu nasıl halledebilirim, bununla ilgili arama yapmak için çok zaman harcadım. Herhangi bir yardım minnettar olur.
katmanco

Benim durumumda işe yaramadı çünkü json koleksiyonu serileştirmeden önce MaxJsonLength ayarlamam gerekiyordu.
César León

Benim durumumda iyi çalışıyor, son kullanıcıya sunmak için datatable'daki "IMAGES" nedeniyle uygulamak zorunda kaldım. Onsuz, anlaşılır bir mesaj olmadan sadece çökün.
Mauro Candido

33

Alt sınıflandırma yerine burada önerildiğiContentResult gibi de kullanabilirsiniz .JsonResult

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

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

2
benim durumumda, atılabilir bir uygulama üzerinde çalışırken, bu çözüm benim için en iyisi oldu. jsonresult uygulaması kaydedildi. Teşekkürler!
Christo


22

Özel bir sınıfa gerek yok. Tek gereken bu:

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

Resultseri hale getirmek istediğiniz veriler nerede .


Hata 137 'System.Web.Mvc.JsonResult', 'MaxJsonLength' için bir tanım içermiyor
PUG

JsonRequestBehavior = JsonRequestBehavior.AllowGet: benim için çalıştı Ancak bu yine de eklemek için gerekli
Dubman

5

Dizeyi oluşturmak için Json.NET kullanıyorsanız json, MaxJsonLengthdeğer ayarlamasına gerek yoktur .

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

4

Bu bağlantıyı takip ederek sorunu çözdüm

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

Kimsenin bir sonuç filtresi kullanmayı önermemesine şaşırdım. Bu, küresel olarak eylem / sonuç ardışık düzenine bağlanmanın en temiz yoludur:

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)
    {
    }
}

Ardından, şunu kullanarak bu sınıfın bir örneğini kaydedin GlobalFilters.Filters:

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

2

LINQ ifadenizde yalnızca ihtiyacınız olan alanları tanımlamayı deneyebilirsiniz.

Misal. Id, Name, Phone ve Picture (bayt dizisi) içeren bir Modeliniz olduğunu ve json'dan bir seçim listesine yüklemeniz gerektiğini hayal edin .

LINQ Sorgusu:

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

Buradaki sorun, tüm alanları alan " u seçin " dir. Yani, eğer büyük resimlerin varsa, booomm.

Nasıl çözülür? çok, çok basit.

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

En iyi uygulamalar, yalnızca kullanacağınız alanı seçmektir.

Hatırlamak. Bu basit bir ipucudur, ancak birçok ASP.NET MVC geliştiricisine yardımcı olabilir.


1
Bu durumda kullanıcının verilerini filtrelemek istediğini varsaymam. Bazı kişilerin veritabanından büyük miktarda satırı geri getirme gereksinimleri var ...
Simon Nicholls

2

Alternatif ASP.NET MVC 5 Düzeltmesi:

Benim durumumda, istek sırasında hata meydana geliyordu. Benim senaryomdaki en iyi yaklaşım JsonValueProviderFactory, düzeltmeyi global projeye uygulayan ve global.csdosyayı bu şekilde düzenleyerek yapılabilen gerçek olanı değiştirmektir .

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

bir web.config girişi ekleyin:

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

ve ardından aşağıdaki iki sınıfı oluşturun

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

Bu temelde, içinde bulunan varsayılan uygulamanın tam bir kopyasıdır, System.Web.Mvcancak yapılandırılabilir bir web.config appsetting değerinin eklenmesiyle birlikte 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;
    }
}

Çok teşekkür ederim !
larizzatg

1

Eylemi olarak değiştirene kadar yukarıdakilerin hiçbiri benim için işe yaramadı [HttpPost]. ve ajax türünü 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);
            ..
            ..
            ...

    }

Ve ajax şöyle çağırır

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

MVC 4'te benim için düzeltme oldu.


0

Kodunuz bir JsonResult nesnesi döndürmeden önce yapılandırma bölümünden manuel olarak okumanız gerekir. Web.config'den tek satırda okuyun:

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

Web.config dosyasında yapılandırma öğesini tanımladığınızdan emin olun


0

bu benim için çalıştı

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

0

biraz başka durum var - veriler istemciden sunucuya gönderilir. denetleyici yöntemini kullandığınızda ve model çok büyükse:

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

sistem "JSON JavaScriptSerializer kullanılarak serileştirme veya seriyi kaldırma sırasında hata oluştu. Dizenin uzunluğu maxJsonLength özelliğinde ayarlanan değeri aşıyor. Parametre adı: girdi"

Bu durumda yardımcı olmak için yalnızca Web.config ayarlarının değiştirilmesi yeterli değildir. Ek olarak, büyük veri modeli boyutlarını desteklemek için mvc json serileştiriciyi geçersiz kılabilir veya Talep'ten modeli manuel olarak kaldırabilirsiniz. Denetleyici yönteminiz şu hale gelir:

   [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

Controller'dan görünümü geri döndürüyorsanız ve cshtml'de json'da kodlarken görünüm çantası verilerinin uzunluğunu artırmak istiyorsanız bu kodu cshtml'ye koyabilirsiniz.

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

var dataJsonOnActionGrid1 = @Html.Raw(userInfoJson);

Şimdi dataJsonOnActionGrid1 js sayfasından erişilebilecek ve doğru sonuç alacaksınız.

Teşekkürler

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.