Avatar ·

Можно ли установить неограниченную длину для maxJsonLength в web.config?

Привет, коллеги! Столкнулся с проблемой при передаче большого JSON-объекта из контроллера ASP.NET MVC на клиент. У меня есть метод действия, который возвращает данные через JsonResult: ```csharp public JsonResult GetLargeData() { var data = GetHugeListOfObjects(); // содержит около 50000 записей return Json(data, JsonRequestBehavior.AllowGet); } ``` На клиенте (jQuery) я получаю ошибку: "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property." Я знаю, что можно увеличить maxJsonLength в web.config: ```xml ``` Но это кажется костылём. Можно ли вообще убрать ограничение, установив maxJsonLength в int.MaxValue или бесконечность? Или есть более правильный способ передавать большие JSON-данные? Может, использовать другой сериализатор? Подскажите, как это решается в продакшене. Заранее спасибо! <<>>

Почему нельзя убрать ограничение полностью

Технически вы можете установить maxJsonLength в int.MaxValue (2 147 483 647), но это не рекомендуется по нескольким причинам:

  • Безопасность: злоумышленник может отправить гигантский JSON и вызвать OutOfMemoryException на сервере
  • Производительность: сериализация/десериализация огромных объектов "съедает" CPU и память
  • Сетевая нагрузка: передача мегабайт JSON через HTTP может "повесить" клиент

Правильное решение: пагинация на сервере

Лучший подход — не передавать все данные сразу, а разбить их на страницы. Вот пример реализации:

// Контроллер
public JsonResult GetLargeData(int page = 1, int pageSize = 100)
{
    var allData = GetHugeListOfObjects();
    var pagedData = allData
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .Select(item => new {
            item.Id,
            item.Name,
            item.Value
        });
    
    return Json(new {
        items = pagedData,
        totalCount = allData.Count,
        currentPage = page,
        pageSize = pageSize
    }, JsonRequestBehavior.AllowGet);
}

// Клиент (jQuery)
function loadPage(page) {
    $.getJSON('/Controller/GetLargeData', { page: page, pageSize: 100 }, function(data) {
        // Обработка data.items
        // data.totalCount, data.currentPage для пагинации
    });
}

Альтернатива: замена сериализатора на Newtonsoft.Json

Если пагинация не подходит и данные действительно нужны все сразу (например, для экспорта), используйте Newtonsoft.Json (Json.NET). Он не имеет встроенного ограничения maxJsonLength:

using Newtonsoft.Json;

public ActionResult GetLargeData()
{
    var data = GetHugeListOfObjects();
    var json = JsonConvert.SerializeObject(data);
    return Content(json, "application/json");
}

Установите пакет через NuGet: Install-Package Newtonsoft.Json

Настройка maxJsonLength в web.config (если очень нужно)

Если вы всё же решили увеличить лимит, делайте это осознанно:

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

Но помните: int.MaxValue — это ~2 ГБ строки JSON в памяти. Это может убить сервер при нескольких одновременных запросах.

Рекомендация для продакшена

  • Всегда используйте пагинацию для списков данных
  • Для экспорта — генерируйте файл на сервере и отдавайте ссылку на скачивание
  • Если данные реально огромные (сотни тысяч записей) — используйте потоковую передачу (Stream)
  • Максимальный разумный лимит maxJsonLength — 10-20 МБ (10 485 760 - 20 971 520)
<<>>

Использование сжатия данных

Если вы не можете изменить архитектуру и всё ещё передаёте большие JSON-объекты, включите сжатие на уровне IIS или в ASP.NET. Это уменьшит размер передаваемых данных в 3-10 раз.

// В Global.asax.cs
protected void Application_Start()
{
    // Включаем динамическое сжатие
    GlobalFilters.Filters.Add(new CompressFilter());
}

// Класс фильтра
public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext.Request;
        var response = filterContext.HttpContext.Response;
        
        if (request.Headers["Accept-Encoding"] != null)
        {
            if (request.Headers["Accept-Encoding"].Contains("gzip"))
            {
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                response.Headers.Add("Content-Encoding", "gzip");
            }
            else if (request.Headers["Accept-Encoding"].Contains("deflate"))
            {
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                response.Headers.Add("Content-Encoding", "deflate");
            }
        }
    }
}

Также можно настроить сжатие в IIS через web.config:

<system.webServer>
  <urlCompression doStaticCompression="true" doDynamicCompression="true"/>
</system.webServer>

Сжатие не решает проблему ограничения maxJsonLength на сервере, но уменьшает нагрузку на сеть и клиентскую сторону.