title: DataTable - Invalid Json Response
body: <p>I am trying to make a dynamic master-detail data table and am getting stuck creating the master table, let alone the detail one!</p>
  
  <p>I am using C# web service to fetch the data and keep getting "Invalid JSON Response" error. I used Chrome developer tool and there is no error getting the data. </p>
  
  <p>Web service API returns the data as JSON sting:</p>
  
  <pre><code>"[{\"Name\":\"County Tax\",\"ExpenseTypeID\":37},{\"Name\":\"Education\",\"ExpenseTypeID\":36},{\"Name\":\"Medical\",\"ExpenseTypeID\":35}]"
  </code></pre>
  
  <p>And when I check XHR Response in Chrome, it shows:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;string xmlns="http://tempuri.org/"&gt;[{"Name":"County Tax","ExpenseTypeID":37},{"Name":"Education","ExpenseTypeID":36},{"Name":"Medical","ExpenseTypeID":35}]&lt;/string&gt;
  </code></pre>
  
  <p>I used JSONLint to validate the JSON and it validates (minus the &lt;string ...&gt;...&lt;/string&gt;).</p>
  
  <p>This is how the code is setup:</p>
  
  <pre><code>&lt;table id="typesDataTable" class="table table-responsive table-striped table-bordered table-hover" width="100%"&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;&lt;/th&gt;
              &lt;th&gt;Expense Type&lt;/th&gt;
              &lt;th style="display: none"&gt;ExpenseTypeID&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
      &lt;/tbody&gt;
      &lt;tfoot&gt;
      &lt;/tfoot&gt;
  &lt;/table&gt;             
  </code></pre>
  
  <p>Javascript:</p>
  
  <pre><code>var typesDataTable = new Object;
  
  $(document).ready(function () {
      buildTypesDataTable();
      addTypesDataTableListener();
  } );
  
  function buildTypesDataTable() {debugger
      if ($.isEmptyObject(typesDataTable)) {
          typesDataTable = $("#typesDataTable").DataTable({
              lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
              pageLength: 10,
              dom: "tip",
              serverSide: true,
              pagingType: "simple",
              autowidth: false,
              language: {
                  emptyTable: "No Expense Types were found."
              },
              ajax: {
                  url: "../services/exp.asmx/GetAllExpenseTypes",
                  type: "POST"
              },
              columns: [
                  {
                      className: 'details-control',
                      orderable: false,
                      data: null,
                      width: "5%",
                      defaultContent: '&lt;img class="details-control-mouseover" src="../assets/images/details_transparent_background.png" title="Click to see included parts." alt="Click to see included parts."/&gt;'
                  },
                  { data: "Name", width: "85%" },
                  { data: "ExpenseTypeID", "visible": false, "searchable": false }
              ],
              order: [[1, "asc"]]
          });
      }
  }
  
  function addTypesDataTableListener() {
      // Add event listener for opening and closing details
      $('#typesDataTable tbody').on('click', 'td.details-control', function () {
          var tr = $(this).closest('tr');
          var row = typesDataTable.row(tr);
  
          if (row.child.isShown()) {
              // This row is already open - close it
              row.child.hide();
              tr.removeClass('shown');
          }
          else {
              // Add the html table shell of the datatable.
              row.child(formatTypesDataTableDetailRow(iTableCounter)).show();
  
              //show the datatable row.
              tr.addClass('shown');
  
              // try datatable stuff
              buildSubTypesDataTable(row.data(), iTableCounter);
              iTableCounter = iTableCounter + 1;
          }
      });
  }
  </code></pre>
  
  <p><strong>Update - the fix</strong></p>
  
  <pre><code>$(document).ready(function () {
      var url = "../services/exp.asmx/GetAllExpenseTypes";
      var params = '';
      populteTypesTable(url, params);
      //buildTypesDataTable();
      addTypesDataTableListener();
  } );
  
  
  var tblExpType = $("#typesDataTable").DataTable({
      jQueryUI: true,
      data: [],
      dom: 'lfrtip',
      stateSave: true,
      stateDuration: 60 * 10,
      "lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "All"]],
      order: [ [1, "asc"]],
      autoWidth: false,
      pagingType: "full_numbers",
      "oLanguage": {
          "sEmptyTable": "No Expense Types were found."
      },
      "columns": [
          {
              "className": 'details-control',
              "orderable": false,
              "data": null,
              "defaultContent": ''
          }, {
              "data": "Name"
          }, {
              "data": "ExpenseTypeID"
          }
      ],
      "columnDefs": [
          {
              "targets": [2],
              "visible": false,
              "searchable": false
          },
          {
              "width": "5%",
              "targets": [0]
          },
          {
              "width": "85%",
              "targets": [1]
          }
      ],
      "pageLength": -1,
      processing: true,
      deferRender: true
  });
  
  function populteTypesTable(ws_url, parameters) {
      $.ajax({
          type: "POST",
          dataType: "json",
          contentType: "application/json; charset=utf-8",
          url: ws_url,
          cache: false,
          data: parameters,
      }).done(function (result) {debugger
          tblExpType.clear().draw();
          if (!result || result.d === "") {
              $('#divType').hide();
          }
          else {
              jResult = JSON.parse(result.d); // This is what I needed to get the correct JSON string
              tblExpType.rows.add(jResult).draw();
              tblExpType.columns([2]).visible(false);
              var currPage = parseInt($('#hfCurrPage').val());
              tblExpType.page(currPage).draw(false);
          }
      }).fail(function (jqXHR, textStatus, errorThrown) {debugger
          alert(textStatus + ' - ' + errorThrown + '\n' + jqXHR.responseText);
      });
  }
  </code></pre>