Search code examples
asp.netajaxjsondatatableswebmethod

How do you send and receive JSON with jQuery.dataTables 1.10 to a ASP.NET WebMethod backend?


Version 1.10 of jQuery DataTables changes a ton of things from the previous versions of DataTables, including how it handles the Ajax requests and responses.

The developers of the library do not have any experience working with an ASP.NET backend, so although some of the nuances of WebMethods have been brought up to them in the past, they apparently didn't consider them in this version.

For example, the dataSrc DataTables option should be where we deal with the fact that ASP.NET WebMethods wrap all of their Ajax responses with {d: [response]}.

Instead, DataTables only looks at the dataSrc setting to find the data property, not the rest of the required response information (draw, recordsTotal, recordsFiltered, and error). My memory could be incorrect, but I'm pretty sure the dataSrc setting used to handle this just fine.


Solution

  • Below is my solution. There may be an easier way to do this, but the way I setup dataTables below seemed to be most reusable way of sending and receiving JSON to a ASP.NET WebMethod. Please post other ways that have worked for you. Hopefully someone will have a less wonky way of doing the "d" thing.

    var $table = $('#TableId');
    var url = 'page.aspx/WebMethodName';
    var extraData = {
        something: 'value1',
        somethingElse: 'value2'
    };
    

    Event handler handles receiving the data from the server. I move everything from the d property into the root of the object.

    $table.on('xhr.dt', function (e, settings, json)
                    {
                        /// <summary>
                        /// Fix for asp.net WebMethod compatibility.
                        /// If json has a d property, then response came from a WebMethod. 
                        /// DataTables needs the contents of the d property to be in the root.
                        /// </summary>
                        /// <param name="e">The jQuery event object.</param>
                        /// <param name="settings">The jquery.DataTables settings object.</param>
                        /// <param name="json">The data returned from the server.</param>
    
                        if(json.d)
                        {
                            var data = json.d;
    
                            // Clear out json.d to free up memory
                            json.d = undefined;
    
                            $.extend(json, data);
                        }
    
                        // Note no return - we have to manipulate the data directly in the JSON object.
                        // WHY, OH WHY, CAN'T WE JUST RETURN?
                    }
    );
    

    DataTable initialization. I serialize the data to send to the server as late as possible to give myself plenty of opportunity to add to the request.

    $table.DataTable({
        ajax: {
            {
                url: url,
                type: 'POST',
                contentType: 'application/json',
                processData: false, // important so the raw data makes it to the beforeSend handler
                beforeSend:function(  jqXHR,  settings )
                    {
                        /// <summary>
                        /// Converts to json for transmission and adds any extra data desired.
                        /// </summary>
                        /// <param name="jqXHR">The jqXHR object.</param>
                        /// <param name="settings">The settings object.</param>
                        /// <param name="data">The data that will be sent to the server.</param>
    
                        var data = settings.data;
    
                        // I postponed the serialization as long as possible, so this is the
                        // last chance to attach extra data to send along
                        data.extraData = extraData;
    
    
                        settings.data = JSON.stringify({ WebMethodParameterName: data });
                    }
            }
        }
    });
    

    On the server side I've created classes to model the structure that dataTables sends and requires as a response. T is the type for each row of data. The DataTablesResponse has a constructor overload which takes the request.draw value and sticks it in the response so I don't have to remember.

    [WebMethod]
    public static DataTablesResponse<T> WebMethodName(DataTablesRequest request)
    {
        var response = new DataTablesResponse<T>(request);
    
        // Do something to get my data
        List<T> results = GetMyData();
    
        response.data = results;
        return response;
    }
    

    As a side note, I attempted to post this to the dataTables.net forums, but I can't get it past draft for some reason... so it will live here instead.