This is a migrated thread and some comments may be shown as answers.

Grid Update to controller is null when updating more than 15 records in batch mode

6 Answers 566 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Matt Bowser
Top achievements
Rank 1
Veteran
Matt Bowser asked on 11 Dec 2020, 01:37 PM

Here is the scenario:  I have a grid that is set to GridEditMode.InCell and Batch=true.  I can make changes to up to 15 records in the grid, click save and the data posts back to the controller without issue.  However, if I update greater than 15 records and click save, the postback to the controller works but the data is null.  

I hope that this isn't a product limitation and I've verified that data being posted back is less than the limit of Json serializer.   

A few caveats to my issue:  

1. We have purchased the licensed version, but have not gone through internal channels to actually access the licensed version so I am still using the trial version.  Is it possible that the trial version has a limitation like this?

2. The grid is a nested hierarchical grid and the data being updated is nested 3 deep.

3. While the grid doesn't display all the data, each record being posted back contains a nested json object (see example of data below).  Because of configurable business requirements, the structure cannot be flat.

Any help would be appreciated. Specifically, knowing the save/update method in kendo code that is being called for batch saves with InCell mode.

Here is my grid (higher level nesting is omitted for simplicity):

<script id="agents" type="text/kendo-tmpl">
@(Html.Kendo().Grid<TLCAgentSchedulerShared.Models.AgentDailyScheduleModel>
    ()
    .Name("agent_#=Id#")
    .Columns(columns =>
    {
        //columns.Command(command => { command.Destroy().Text(" "); }).Width(50);
        columns.Command(command => { command.Destroy().Template("<button type='button' onclick='removeAgent(this, setCoEId())' class='btn btn-danger btn-xs'><span class='glyphicon glyphicon-remove' title='Delete'>X</span></button>").Text(" "); }).Width(50);
        columns.Bound(b => b.FullName).Width(100).Title("Agent");
        columns.Bound(b => b.Supervisor).Width(100).Title("Supervisor");
        columns.Bound(b => b.TimeSlot).Width(50).Title("Schedule");
        columns.Bound(b => b.AgentAssignments[0].IsAssigned).Width(70).Title("6:30AM - 8:30AM").EditorTemplateName("Boolean")
        .ClientTemplate(@"<input type='checkbox' \\#: AgentAssignments[0].IsAssigned ? checked='checked' : '' \\# />");
        columns.Bound(b => b.AgentAssignments[1].IsAssigned).Width(70).Title("8:30AM - 3:00PM").EditorTemplateName("Boolean")
        .ClientTemplate(@"<input type='checkbox' \\#: AgentAssignments[1].IsAssigned ? checked='checked' : '' \\# />");
        columns.Bound(b => b.AgentAssignments[2].IsAssigned).Width(70).Title("3:00PM - 5:00PM").EditorTemplateName("Boolean")
        .ClientTemplate(@"<input type='checkbox' \\#: AgentAssignments[2].IsAssigned ? checked='checked' : '' \\# />");
        columns.Bound(b => b.AgentAssignments[3].IsAssigned).Width(70).Title("5:00PM - 7:30PM").EditorTemplateName("Boolean")
        .ClientTemplate(@"<input type='checkbox' \\#: AgentAssignments[3].IsAssigned ? checked='checked' : '' \\# />");
 
        columns.Bound(b => b.AgentAssignments[0].Comments).Title("Comments").Width(195);
 
    })
    .DataSource(dataSource => dataSource
    .Ajax()
    .Events(events => events.Error("error_handler"))
    .Model(model => model.Id(p => p.UserProfileId))
    .Batch(true)
    .Read(read => read.Action("GetDefaultAgentsByPod", "Grid").Data("setDayOfWeek(#=Id#)"))
    .Update(update => update.Action("UpdateDefaultAgentsInPod", "Grid")).Events(events => events.Change("change_handler"))
    //.Destroy(destroy => destroy.Action("RemoveDefaultAgentsInPod", "Grid").Data("setCoEId()")).Events(events => events.Change("change_handler"))
    )
    //.Pageable()
    .HtmlAttributes(new { @class = "agentGrid" })
    .ToolBar(toolbar =>
    {
        toolbar.Save();
        toolbar.Custom().Text("Assign a New Agent").HtmlAttributes(new { onclick = "assignAgent(#=Id#)" });
 
    })
    .Editable(editable => editable.Mode(GridEditMode.InCell).DisplayDeleteConfirmation(false))
 
    .Sortable()
    .ToClientTemplate()
    )
</script>

 

Here is my controller that works fine when less than 15 records have been updated (some security logic has been omitted to avoid potential confidentiality issues), but the key is that both the request object and the agents object are fully populated when less than 15 records:

[HttpPost]
        public async Task<ActionResult> UpdateDefaultAgentsInPod([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IEnumerable<AgentDailyScheduleModel> agents)
        {
//Convert incoming to json
                        string jsonData = JsonConvert.SerializeObject(agents);
            using (var client = new HttpClient())
            {
                using (var response = await client.PostAsync(String.Format("{0}agent/UpdateDefaultAssignmentsByPod/", _baseApiUrl),
                    new StringContent(jsonData, Encoding.UTF8, "application/json")))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    var result = JsonConvert.DeserializeObject<ApiResponse<List<AgentDailyScheduleModel>>>(apiResponse);
                    if (result.IsValid)
                    {
                        agentList = result.ResponseData;
                    }
                    else
                    {
                        return BadRequest(String.Format("There was an error proccessing your request. Message: {0}", result.ResponseMessage));
                    }
                }
            }
            var dsResult = agentList.ToDataSourceResult(request);
            return Json(dsResult);
}

 

Here is what 1 record of data looks like:

[{
    "UserProfileId": 150,
    "NtLogin": "xxxx",
    "FullName": "xxxx",
    "Supervisor": null,
    "TimeSlot": "7:30-19:00",
    "AgentAssignments": [{
            "PodId": 2,
            "PodName": "PODFREpat",
            "DailyAssignmentId": 9070,
            "AgentDefaultScheduleId": 12699,
            "BlockId": 1,
            "IsScheduled": true,
            "IsAssigned": true,
            "IsDefault": true,
            "Date": null,
            "IsBlockFullyScheduled": false,
            "Comments": null,
            "CreatedBy": null,
            "UpdatedBy": null,
            "CreatedOn": "0001-01-01T00:00:00",
            "UpdatedOn": "0001-01-01T00:00:00"
        },
        {
            "PodId": 2,
            "PodName": "PODFRE-pat",
            "DailyAssignmentId": 9071,
            "AgentDefaultScheduleId": 12724,
            "BlockId": 2,
            "IsScheduled": true,
            "IsAssigned": true,
            "IsDefault": true,
            "Date": null,
            "IsBlockFullyScheduled": true,
            "Comments": null,
            "CreatedBy": null,
            "UpdatedBy": null,
            "CreatedOn": "0001-01-01T00:00:00",
            "UpdatedOn": "0001-01-01T00:00:00"
        }, {
            "PodId": 2,
            "PodName": "POD FRE-pat",
            "DailyAssignmentId": 9072,
            "AgentDefaultScheduleId": 12723,
            "BlockId": 3,
            "IsScheduled": true,
            "IsAssigned": true,
            "IsDefault": true,
            "Date": null,
            "IsBlockFullyScheduled": true,
            "Comments": null,
            "CreatedBy": null,
            "UpdatedBy": null,
            "CreatedOn": "0001-01-01T00:00:00",
            "UpdatedOn": "0001-01-01T00:00:00"
        }, {
            "PodId": 2,
            "PodName": "POD FRE-pat",
            "DailyAssignmentId": 9050,
            "AgentDefaultScheduleId": 12722,
            "BlockId": 4,
            "IsScheduled": true,
            "IsAssigned": true,
            "IsDefault": true,
            "Date": null,
            "IsBlockFullyScheduled": false,
            "Comments": null,
            "CreatedBy": null,
            "UpdatedBy": null,
            "CreatedOn": "0001-01-01T00:00:00",
            "UpdatedOn": "0001-01-01T00:00:00"
        }
    ]
}]

 

6 Answers, 1 is accepted

Sort by
0
Tsvetomir
Telerik team
answered on 16 Dec 2020, 11:43 AM

Hi Matt,

Thank you for the provided detailed explanation of the scenario on hand.

The widgets available in the Trial version do not imply limitations. The difference with the licensed version is that you will notice text stating that "Trial version of the suite is used" plugged randomly in the page's HTML.

With that said, there might be an error that is being thrown that prevents the execution of the update. What I can recommend is that you open the devtools of the browser and:

1. Check the console for any potential JavaScript errors.

2. Navigate to the "Network" tab of the devtools. Submit an update request and investigate its response. It should have a return status code 200 and the correct response. If the status code is different, let me know and share the exact message that is returned from the server. 

Looking forward to your reply.

 

Best regards,
Tsvetomir
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Matt Bowser
Top achievements
Rank 1
Veteran
answered on 17 Dec 2020, 04:32 PM

Thanks for responding to this question.

When I submit a request to update less than 15 records the request hits the controller with a collection of AgentDailyScheduleModel objects properly and the server processes the request as it should.

When I submit a request to update more than 15 records the request hits the controller, but the collection of AgentDailyScheduleModels is null and the server responds by returning a 400 BadRequest because there is nothing to process.

There are no javascript errors in the console other than the 400 response when the controller returns.

I also see that in the initial request to the server, the form data being submitted appears to be correct and I compared it to a request that worked where I only submitted 1 record (and had success)

The only thing I can think of is that the form data being submitted exceeds the max size that can be submitted.

Below is the form data posted for one record.  As you can see, it is quite a lot of data, and I can see how it would add up if submitting 15 or more records. 

coeId: 1
models[0].UserProfileId: 293
models[0].NtLogin: xxxxx
models[0].FullName: xxxxxx
models[0].Supervisor: 
models[0].TimeSlot: N/A
models[0].Date: 1
models[0].CreatedBy: 
models[0].UpdatedBy: 
models[0].AgentAssignments[0].PodId: 1
models[0].AgentAssignments[0].PodName: POD BLTWY-Central Bay
models[0].AgentAssignments[0].PodCoverage: 
models[0].AgentAssignments[0].DailyAssignmentId: 3421
models[0].AgentAssignments[0].AgentDefaultScheduleId: 16086
models[0].AgentAssignments[0].BlockId: 1
models[0].AgentAssignments[0].IsScheduled: false
models[0].AgentAssignments[0].IsAssigned: false
models[0].AgentAssignments[0].IsDefault: true
models[0].AgentAssignments[0].Date: 
models[0].AgentAssignments[0].IsBlockFullyScheduled: false
models[0].AgentAssignments[0].Comments: 
models[0].AgentAssignments[0].CreatedBy: 
models[0].AgentAssignments[0].UpdatedBy: 
models[0].AgentAssignments[0].CreatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[0].UpdatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[1].PodId: 1
models[0].AgentAssignments[1].PodName: POD BLTWY-Central Bay
models[0].AgentAssignments[1].PodCoverage: 
models[0].AgentAssignments[1].DailyAssignmentId: 3396
models[0].AgentAssignments[1].AgentDefaultScheduleId: 16085
models[0].AgentAssignments[1].BlockId: 2
models[0].AgentAssignments[1].IsScheduled: false
models[0].AgentAssignments[1].IsAssigned: false
models[0].AgentAssignments[1].IsDefault: true
models[0].AgentAssignments[1].Date: 
models[0].AgentAssignments[1].IsBlockFullyScheduled: false
models[0].AgentAssignments[1].Comments: 
models[0].AgentAssignments[1].CreatedBy: 
models[0].AgentAssignments[1].UpdatedBy: 
models[0].AgentAssignments[1].CreatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[1].UpdatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[2].PodId: 1
models[0].AgentAssignments[2].PodName: POD BLTWY-Central Bay
models[0].AgentAssignments[2].PodCoverage: 
models[0].AgentAssignments[2].DailyAssignmentId: 3407
models[0].AgentAssignments[2].AgentDefaultScheduleId: 16060
models[0].AgentAssignments[2].BlockId: 3
models[0].AgentAssignments[2].IsScheduled: false
models[0].AgentAssignments[2].IsAssigned: false
models[0].AgentAssignments[2].IsDefault: true
models[0].AgentAssignments[2].Date: 
models[0].AgentAssignments[2].IsBlockFullyScheduled: false
models[0].AgentAssignments[2].Comments: 
models[0].AgentAssignments[2].CreatedBy: 
models[0].AgentAssignments[2].UpdatedBy: 
models[0].AgentAssignments[2].CreatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[2].UpdatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[3].PodId: 1
models[0].AgentAssignments[3].PodName: POD BLTWY-Central Bay
models[0].AgentAssignments[3].PodCoverage: 
models[0].AgentAssignments[3].DailyAssignmentId: 3395
models[0].AgentAssignments[3].AgentDefaultScheduleId: 16061
models[0].AgentAssignments[3].BlockId: 4
models[0].AgentAssignments[3].IsScheduled: false
models[0].AgentAssignments[3].IsAssigned: false
models[0].AgentAssignments[3].IsDefault: true
models[0].AgentAssignments[3].Date: 
models[0].AgentAssignments[3].IsBlockFullyScheduled: false
models[0].AgentAssignments[3].Comments: 
models[0].AgentAssignments[3].CreatedBy: 
models[0].AgentAssignments[3].UpdatedBy: 
models[0].AgentAssignments[3].CreatedOn: 0001-01-01T00:00:00
models[0].AgentAssignments[3].UpdatedOn: 0001-01-01T00:00:00

 

 

 

 

 

 

 

 

 

0
Matt Bowser
Top achievements
Rank 1
Veteran
answered on 17 Dec 2020, 06:36 PM

Ok, once I took a look at how much form data was being posted I started googling possible size limitations and found that I may be exceeding the out of the box implementation for form data in a http post request. A lot of the search results had to do with file upload size limitations, but I did find one post (https://www.kelltontech.com/kellton-tech-blog/how-submit-large-number-form-values-aspnet-core) that detailed how to increase size limits.  There are multiple options that can be implemented at the application level or method level.  I chose the application level because I have a number of methods that are moving large amounts of form data.  

I've done one test so far and it seems to have corrected the issue, but I need to do more testing to confirm.  When I push this data from the front end controller to downstream Api services, I am sending it as json data in the body of the request so I don't believe I will have the issue on the Api.

Anyway, the solution is detailed in the url above, but here is what I did to my startup:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services
                .AddControllersWithViews()
                .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
                // Maintain property names during serialization. See:
                // https://github.com/aspnet/Announcements/issues/194
                .AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
                
            // Add Kendo UI services to the services container
            services.AddKendo();
            // This is to increase the size form data posted to controller.
            services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(x => x.ValueCountLimit = 10000);
        }

0
Tsvetomir
Telerik team
answered on 22 Dec 2020, 11:16 AM

Hi Matt,

I am very happy to hear that you have managed to find and resolve the issue on your own. Indeed, the approach that you have undertaken looks fine to me. 

As a side note, in similar cases, I have used third-party libraries that would compress the payload for the request and decompress it on the server-side. However, this is desirable when you would like to avoid modifying the default size of the requests.

In case there is anything else that I can help with, let me know.

 

Best regards,
Tsvetomir
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Sotiris
Top achievements
Rank 1
Veteran
Iron
answered on 05 Apr 2021, 11:38 AM

Hello Tsvetomir,

Could you please elaborate with an example in which third-party libraries are used to compress the payload for the request and decompress it on the server-side?

Best regards,
Sotiris

0
Tsvetomir
Telerik team
answered on 08 Apr 2021, 10:48 AM

Hi Matthew,

I am attaching a sample project that uses the LZString library to compressing/decompress the payload. 

Let me know if additional details are required.

 

Regards,
Tsvetomir
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
Grid
Asked by
Matt Bowser
Top achievements
Rank 1
Veteran
Answers by
Tsvetomir
Telerik team
Matt Bowser
Top achievements
Rank 1
Veteran
Sotiris
Top achievements
Rank 1
Veteran
Iron
Share this question
or