0
votes

I have a Kendo Grid that has columns bound to a related table. The grid shows a fixed 4 level hierarchy that is flattened out: PK_Field, Name, Level_1, Level_2, Level_3 and Level_4.
I bind the Level Columns using this examble from Telerik :

Kendo grid:

 @(Html.Kendo().Grid<MyViewModel>()
  .Name("Grid")
  .Columns(columns =>
  {
      columns.Command(command =>
      {
          command.Edit();
          command.Destroy();        
      }).Width(220);
      columns.Bound(t => t.Name).Width(80);
      columns.Bound(t => t.CreateDate).Width(80);
      columns.ForeignKey(t => t.Level1Id, (System.Collections.IEnumerable)ViewData["Level1"], "Id", "Text").Title("Level 1").EditorTemplateName("EditLevel1Id");
      columns.ForeignKey(t => t.Level2Id, (System.Collections.IEnumerable)ViewData["Level2"], "Id", "Text").Title("Level 2").EditorTemplateName("EditLevel2Id");
      columns.ForeignKey(t => t.Level3Id, (System.Collections.IEnumerable)ViewData["Level3"], "Id", "Text").Title("Level 3").EditorTemplateName("EditLevel3Id");
      columns.ForeignKey(t => t.Level4Id, (System.Collections.IEnumerable)ViewData["Level4"], "Id", "Text").Title("Level 4").EditorTemplateName("EditLevel4Id");
      columns.Bound(t => t.Username).Width(100);
  })

Server side:

private void PopulateCategories()
   {
       var dataContext = new SampleEntities();
       var categories = dataContext.Categories
                   .Select(c => new CategoryViewModel {
                       CategoryID = c.CategoryID,
                       CategoryName = c.CategoryName
                   })
                   .OrderBy(e => e.CategoryName);

       ViewData["Level1"] = categories;    
   }

The columns Level_1 to Level_4 each have their own ViewData variable.

When the amount of data used for Level_4 become large, the "The length of the string exceeds the value set on the maxJsonLength property" error appears.

All my server-side methods are set to use MaxJsonLength = Int32.MaxValue but the ViewData variables are not affected by this, and so they cause the error when they get too big.

How can I prevent large ViewData variables from producing the error?

EDIT

The editing templates -
Level 1:

@using Kendo.Mvc.UI

@(Html.Kendo().DropDownListFor(m => m)
      .AutoBind(false)
      .OptionLabel("Select a value...")
      .DataTextField("Text")
      .DataValueField("Id")
      .DataSource(dataSource =>
      {
          dataSource.Read(read => read.Action("GetLevel1Descriptions", "MyAdmin").Data("filter1Descriptions"))
          .ServerFiltering(true);
      })
      .HtmlAttributes(new { id = "Level1Id" })
)
@Html.ValidationMessageFor(m => m)

Level 2:

@using Kendo.Mvc.UI

@(Html.Kendo().DropDownListFor(m => m)
      .AutoBind(false)
      .OptionLabel("Select a value...")
      .DataTextField("Text")
      .DataValueField("Id")
      .DataSource(dataSource =>
      {
          dataSource.Read(read => read.Action("GetLevel2Descriptions", "Admin").Data("filterLevel2Descriptions"))
          .ServerFiltering(true);
      })
      .CascadeFrom("Level1Id")
      .HtmlAttributes(new { id = "Level2Id" })
)
@Html.ValidationMessageFor(m => m)

Level3 and Level4 follow Level2 pattern

1

1 Answers

2
votes

Here are a couple of things I did to resolve the issue with maxJson Length being hit:

1) Web.config changes:

<system.web>
   <httpRuntime targetFramework="4.5" maxRequestLength="50000000" />
   all other settings remove for Brevity.....
</system.web>


 <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="2147483648" />

      </requestFiltering>
    </security>
    all other settings remove for Brevity.....
 </system.webServer>


<system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="50000000" recursionLimit="500">
          <converters></converters>
        </jsonSerialization>
      </webServices>
    </scripting>
  </system.web.extensions>

2) Returned a custom version of the JsonResult object using these three variations:

protected virtual JsonResult GetLargeJson<T>(List<T> model, DataSourceRequest request = null, bool denyGet = true)
{
    JsonResult result = null;
    if (request == null)
    {
        result = Json(model);
    }
    else
    {
        result = Json(model.ToDataSourceResult(request, ModelState));
    }


    result.MaxJsonLength = Int32.MaxValue;
    result.JsonRequestBehavior = (denyGet) ? JsonRequestBehavior.DenyGet : JsonRequestBehavior.AllowGet;
    return result;
}

protected virtual JsonResult GetLargeJson(DataTable model, DataSourceRequest request = null, bool denyGet = true)
{
    JsonResult result = null;
    if (request == null)
    {
        result = Json(model);
    }
    else
    {
        if (!ModelState.IsValid)
        {
            DataSourceResult response = model.ToDataSourceResult(request);
            response.Errors = ModelState.SerializeErrors();


            result = Json(response);

        }
        else
        {
            result = Json(model.ToDataSourceResult(request));
        }
    }

    result.MaxJsonLength = Int32.MaxValue;
    result.JsonRequestBehavior = (denyGet) ? JsonRequestBehavior.DenyGet : JsonRequestBehavior.AllowGet;


    return result;


}



protected virtual JsonResult GetLargeJson<T>(T model, DataSourceRequest request = null, bool denyGet = true)
{
    JsonResult result = null;
    if (request == null)
    {
        result = Json(model);
    }
    else
    {
        result = Json(new[] { model }.ToDataSourceResult(request, ModelState));
    }

    result.MaxJsonLength = Int32.MaxValue;
    result.JsonRequestBehavior = (denyGet) ? JsonRequestBehavior.DenyGet : JsonRequestBehavior.AllowGet;


    return result;


}

Where type T is a generic. This way I have a standard way of dealing with large objects and ensure they don't blow up an error.

I would suggest maybe looking at an alternative way of handling custom editing rather than booting everything in the ViewData object as that will become exceptionally large as you are experiencing and if the data is being used for drop downs/ multiselect type controls then using ajax versions of the controls may result in better performance in the long term. I'm happy to help with suggesting a cleaning way of performing this type of operation if you can give more details about the editing templates you are using.