Ngoại lệ MaxJsonLpm trong ASP.NET MVC trong JavaScriptSerializer


122

Trong một trong những hành động điều khiển của tôi, tôi sẽ trả lại một số rất lớn JsonResultđể điền vào lưới.

Tôi nhận được InvalidOperationExceptionngoại lệ sau :

Lỗi trong quá trình tuần tự hóa hoặc giải tuần tự hóa bằng cách sử dụng JSON JavaScriptSerializer. Độ dài của chuỗi vượt quá giá trị được đặt trên thuộc tính maxJsonLpm.

Rất tiếc, việc đặt thuộc maxJsonLengthtính thành web.configgiá trị cao hơn không cho thấy hiệu quả.

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

Tôi không muốn chuyển nó trở lại như một chuỗi như được đề cập trong câu trả lời SO này .

Trong nghiên cứu của tôi, tôi đã xem qua bài đăng trên blog này , nơi viết một bài viết ActionResult(ví dụ LargeJsonResult : JsonResult) được đề xuất để bỏ qua hành vi này.

Đây có phải là giải pháp duy nhất?
Đây có phải là một lỗi trong ASP.NET MVC?
Tui bỏ lỡ điều gì vậy?

Bất kỳ trợ giúp sẽ được đánh giá cao nhất.


2
Các giải pháp của bạn hoạt động trên MVC 3.
MatteoSp

1
@Matteo Bạn có chắc không? Đây là một câu hỏi cũ và tôi không thể nhớ nhưng rõ ràng tôi đã gắn thẻ nó là MVC3. Thật không may, tôi không thể xem phiên bản / ngày khi nó được sửa / đóng: aspnet.codeplex.com/workitem 43236
Martin Buberl

1
Chắc chắn, tôi đang làm việc với MVC 3 và nó hoạt động. Và may mắn thay, vì trong MVC 3, bạn không có thuộc tính "MaxJsonLpm" được trích dẫn trong câu trả lời được chấp nhận.
MatteoSp

Câu trả lời:


228

Có vẻ như điều này đã được sửa trong MVC4.

Bạn có thể làm điều này, hoạt động tốt cho tôi:

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

Tôi đang đặt chuỗi json thành thuộc tính ViewBag.MyJsonString nhưng gặp lỗi tương tự trong chế độ xem của tôi khi chạy trên dòng javascript sau: var myJsonObj = @ Html.Raw (Json.Encode (ViewBag.MyJsonString));
Faisal Mq

1
Xin chào @orionedvards, @ GG, @ MartinBuberl Tôi đang gặp phải vấn đề maxJson tương tự nhưng khi đăng dữ liệu lên bộ điều khiển, Làm thế nào tôi có thể xử lý vấn đề này, tôi đã dành rất nhiều thời gian để tìm kiếm về vấn đề này.
katmanco

Trong trường hợp của tôi không hoạt động vì tôi phải đặt MaxJsonLpm trước khi json nối tiếp bộ sưu tập.
César León

Trong trường hợp của tôi hoạt động tốt, tôi đã phải thực hiện nó vì "HÌNH ẢNH" trong khả năng lưu trữ để trình bày cho người dùng cuối cùng. Không có nó, chỉ cần sụp đổ mà không có bất kỳ thông điệp dễ hiểu.
Mauro Candido

33

Bạn cũng có thể sử dụng ContentResultnhư được đề xuất ở đây thay vì phân lớp JsonResult.

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

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

2
trong trường hợp của tôi, làm việc trên một ứng dụng vứt đi, giải pháp này hiệu quả nhất với tôi. lưu thực hiện jsonresult. cảm ơn!
Christo


22

Không cần một lớp tùy chỉnh. Đây là tất cả những gì cần thiết:

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

nơi Resultlà dữ liệu bạn muốn sắp đặt.


Lỗi 137 'System.Web.Mvc.JsonResult' không chứa định nghĩa cho 'MaxJsonLpm'
PUG

Điều này làm việc cho tôi, tuy nhiên vẫn cần thêm: JsonRequestBehavior = JsonRequestBehavior.AllowGet
DubMan

5

Nếu sử dụng Json.NET để tạo jsonchuỗi, nó không cần đặt MaxJsonLengthgiá trị.

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

4

Tôi đã giải quyết vấn đề bằng cách theo liên kết này

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

Tôi ngạc nhiên không ai đề nghị sử dụng bộ lọc kết quả. Đây là cách sạch nhất để kết nối toàn cầu vào đường dẫn hành động / kết quả:

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

Sau đó, đăng ký một thể hiện của lớp đó bằng cách sử dụng GlobalFilters.Filters:

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

2

Bạn có thể thử xác định trong biểu thức LINQ của mình chỉ trường mà bạn sẽ cần.

Thí dụ. Hãy tưởng tượng rằng bạn có một Model có Id, Name, Phone và Picture (mảng byte) và cần tải từ json vào một danh sách chọn.

Truy vấn LINQ:

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

Vấn đề ở đây là " chọn u " có được tất cả các trường. Vì vậy, nếu bạn có hình ảnh lớn, booomm.

Giải quyết thế nào? rất, rất đơn giản

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

Thực tiễn tốt nhất là chỉ chọn lĩnh vực mà bạn sẽ sử dụng.

Nhớ lại. Đây là một mẹo đơn giản, nhưng có thể giúp nhiều nhà phát triển ASP.NET MVC.


1
Tôi sẽ không cho rằng người dùng trong trường hợp này muốn lọc dữ liệu của họ. Một số người có yêu cầu mang về một lượng lớn hàng từ cơ sở dữ liệu ...
Simon Nicholls

2

Thay thế ASP.NET MVC 5:

Trong trường hợp của tôi, lỗi đã xảy ra trong khi yêu cầu. Cách tiếp cận tốt nhất trong kịch bản của tôi là sửa đổi thực tế JsonValueProviderFactoryáp dụng sửa lỗi cho dự án toàn cầu và có thể được thực hiện bằng cách chỉnh sửa global.cstệp như vậy.

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

thêm một mục web.config:

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

và sau đó tạo hai lớp sau

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

Về cơ bản, đây là một bản sao chính xác của cài đặt mặc định được tìm thấy System.Web.Mvcnhưng có thêm giá trị ứng dụng web.config có thể định cấu hình 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;
    }
}

Cảm ơn bạn rất nhiều !
larizzatg

1

Không có cách nào ở trên phù hợp với tôi cho đến khi tôi thay đổi Hành động như [HttpPost]. và thực hiện các loại ajax như 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);
            ..
            ..
            ...

    }

Và cuộc gọi ajax là

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

Là bản sửa lỗi cho tôi trong MVC 4.


0

Bạn cần đọc từ phần cấu hình theo cách thủ công trước khi mã của bạn trả về một đối tượng JsonResult. Chỉ cần đọc từ web.config trong một dòng duy nhất:

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

Hãy chắc chắn rằng bạn đã xác định thành phần cấu hình trong web.config


0

cái này làm việc cho tôi

        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ó một trường hợp khác - dữ liệu được gửi từ máy khách đến máy chủ. Khi bạn đang sử dụng phương thức và mô hình bộ điều khiển là rất lớn:

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

hệ thống đưa ra ngoại lệ như thế này "Lỗi trong quá trình tuần tự hóa hoặc giải tuần tự hóa bằng cách sử dụng JSON JavaScriptSerializer. Độ dài của chuỗi vượt quá giá trị được đặt trên thuộc tính maxJsonLpm. Tên tham số: input"

Chỉ thay đổi cài đặt Web.config là không đủ để trợ giúp trong trường hợp này. Ngoài ra, bạn có thể ghi đè bộ nối tiếp mvc json để hỗ trợ kích thước mô hình dữ liệu khổng lồ hoặc mô hình khử lưu thủ công từ Yêu cầu. Phương thức điều khiển của bạn trở thành:

   [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

Bạn có thể đặt mã này vào cshtml nếu bạn đang quay lại chế độ xem từ bộ điều khiển và bạn muốn tăng thời lượng của dữ liệu túi xem trong khi mã hóa bằng json trong cshtml

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

var dataJsonOnActionGrid1 = @Html.Raw(userInfoJson);

Hiện nay, dataJsonOnActionGrid1 sẽ được tích lũy trên trang js và bạn sẽ nhận được kết quả thích hợp.

Cảm ơn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.