Just want to share this in case anyone else runs into it. When a Kendo UI grid is bound to a SignalR datasource and Batch = true for that datasource, the server will begin responding with the following during create/update/destroy method calls:
{"I":"1","E":"There was an error invoking Hub method 'tranimporterrorshub.update'."}
This is because the automatically generated JSON is in an incorrect format to bind to your hub methods.
Example hub method:
public class ExampleHub : Hub{ public DataSourceResult Read(DataSourceRequest request) { // read operations here } public async Task Update(IEnumerable<ExampleViewModel> rows) { foreach (var row in rows) { // Update operations here } } public async Task Destroy(IEnumerable<ExampleViewModel> rows) { foreach (var row in rows) { // Delete operations here } }}
When the JSON for create/update/destroy is generated, it is something like this:
data:{"H":"exampleshub","M":"update","A":[{"models":[{"Id":1,"Example":"Test"},{"Id":3,"Example":"Test2"}]}],"I":2}
If you look closely, the "A" property in the JSON starts with a "[", which indicates an array, even though there is NOT an array of models. ASP.NET MVC SignalR does not support a call with the "data" being an array (must be an object or basic type) and the following exception is thrown:
Exception: Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.dll ("Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[ExampleViewModel]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path 'models', line 1, position 10.").
I found a fix for this. Simply add this function and wire it up to the parameterMap property for your DataSource:
function datasourceParameterMap(data, type) { if (type !== 'read' && data.models) { return data.models; } else { return data; }}
Hope this helps someone else so that they don't have to figure it out the hard way.