Kendo UI Grid Update unable to deserialize JSON in

2019-09-05 01:49发布

问题:

I am using Kendo UI feature Grid and trying to implement batch Update functionality.

Here is what I have done so far:

           $(document).ready(function () {
             ("#grid").kendoGrid({
               dataSource:
                   {
                   type: "json",
                   transport:
                        {
                            read: function (options) {
                                $.ajax({
                                    url: "IndicatorService.svc/GetIndicators/" + speedID,
                                    dataType: "json",
                                    success: function (result) {
                                        options.success(result);
                                    }
                                });

                            },

                            update: function(options) {
                                $.ajax({
                                    type: "POST",
                                    url: "IndicatorService.svc/UpdateIndicators",
                                    dataType: "json",
                                    contentType: "application/json",
                                    data: {
                                        Indicators: kendo.stringify(options.data.models)
                                    },
                                    success: function(result) {
                                        // notify the data source that the request succeeded
                                        options.success(result);
                                    },
                                    error: function(result) {
                                        // notify the data source that the request failed
                                        options.error(result);
                                    }
                                });
                            }



                        },
                   batch: true,
                   schema: {
                       type: 'json',
                       model: {
                           id: "IndicatorUID",
                           fields: {
                               IndicatorUID: { type: "guid" },
                               IndicatorName: { type: "string" },
                               LastUpdatedBy: { type: "string" },
                               LastUpdatedDate: { type: "date" },
                               POPL3Commit: { type: "date" },
                               ActualFinish: { type: "date" },
                               PlanOfRecord: { type: "date" },
                               Trend: { type: "date" }

                           }
                       }
                   },
                   pageSize: 10

               },
               height: 430,
               filterable: true,
               sortable: true,
               pageable: true,
               toolbar: ["create", "save", "cancel"],
               editable: true,

               columns: [
                   {
                       field: "IndicatorName",
                       title: "IndicatorName",
                       width: 120
                   },
                   {
                       field: "POPL3Commit",
                       title: "POPL3Commit",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "PlanOfRecord",
                       title: "PlanOfRecord",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "Trend",
                       title: "Trend",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "ActualFinish",
                       title: "ActualFinish",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "LastUpdatedBy",
                       title: "LastUpdatedBy",
                       width: 120
                   },
                   {
                       field: "LastUpdatedDate",
                       title: "LastUpdatedDate",
                       width: 120
                   }
               ]
           });
       });

My View Model (IndicatorGridLineItem)

[DataContractAttribute]
public class IndicatorGridLineItem
{
    #region Private Properties

    /// <summary>
    /// Indicator UID
    /// </summary>
    private Guid _indicatorUID { get; set; }

    /// <summary>
    /// The _indicator name
    /// </summary>
    private string _indicatorName { get; set; }

    /// <summary>
    /// The _commit
    /// </summary>
    private DateTime _pOPL3Commit { get; set; }

    /// <summary>
    /// The _p OR
    /// </summary>
    private DateTime _planOfRecord { get; set; }

    /// <summary>
    /// The _trend
    /// </summary>
    private DateTime _trend { get; set; }

    /// <summary>
    /// The _trend color
    /// </summary>
    private string _trendColor { get; set; }

    /// <summary>
    /// The _actual finish
    /// </summary>
    private DateTime _actualFinish { get; set; }

    /// <summary>
    /// The _last updated by
    /// </summary>
    private string _lastUpdatedBy { get; set; }

    /// <summary>
    /// The _last updated date
    /// </summary>
    private DateTime _lastUpdatedDate { get; set; }

    #endregion Private Properties

    #region Public Properties

    /// <summary>
    /// Indicator UID
    /// </summary>
    [DataMember]
    public string IndicatorUID
    {
        get 
        { 
            return _indicatorUID.ToString(); 
        }
        set 
        {
            Guid newGuid;

            if (Guid.TryParse(value, out newGuid))
                _indicatorUID = newGuid;
            else
                _indicatorUID = Guid.Parse("00000000-0000-0000-0000-000000000000"); 
        }
    }

    /// <summary>
    /// The indicator name
    /// </summary>
    [DataMember]
    public string IndicatorName
    {
        get 
        { 
            return _indicatorName; 
        }
        set 
        { 
            _indicatorName = value; 
        }
    }

    /// <summary>
    /// The commit
    /// </summary>
    [DataMember]
    public string POPL3Commit
    {
        get 
        {
            return DateOutputGenerator(_pOPL3Commit); 
        }
        set 
        {
            _pOPL3Commit = DateInputGenerator(value);
        }
    }

    /// <summary>
    /// The POR
    /// </summary>
    [DataMember]
    public string PlanOfRecord
    {
        get 
        {    
            return DateOutputGenerator(_planOfRecord); 
        }
        set 
        { 
            _planOfRecord = DateInputGenerator(value); 
        }
    }

    /// <summary>
    /// The trend
    /// </summary>
    [DataMember]
    public string Trend
    {
        get 
        {    
            return DateOutputGenerator(_trend); 
        }
        set 
        { 
            _trend = DateInputGenerator(value); 
        }
    }

    /// <summary>
    /// The trend color
    /// </summary>
    [DataMember]
    public string TrendColor
    {
        get 
        {
            return String.IsNullOrEmpty(_trendColor) ? _trendColor : ""; 
        }
        set 
        { 
            _trendColor = value; 
        }
    }

    /// <summary>
    /// The actual finish
    /// </summary>
    [DataMember]
    public string ActualFinish
    {
        get 
        {    
            return DateOutputGenerator(_actualFinish); 
        }
        set 
        { 
            _actualFinish = DateInputGenerator(value); 
        }
    }

    /// <summary>
    /// The last updated by
    /// </summary>
    [DataMember]
    public string LastUpdatedBy
    {
        get 
        { 
            return String.IsNullOrEmpty(_lastUpdatedBy) ? _lastUpdatedBy : ""; 
        }
        set 
        { 
            _lastUpdatedBy = value; 
        }
    }
    /// <summary>
    /// The last updated date
    /// </summary>
    [DataMember]
    public string LastUpdatedDate
    {
        get 
        {    
            return DateOutputGenerator(_lastUpdatedDate); 
        }
        set 
        { 
            _lastUpdatedDate = DateInputGenerator(value); 
        }
    }

    #endregion Public Properties

    /// <summary>
    /// Dates the output generator.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    protected string DateOutputGenerator(DateTime value)
    {
        DateTime beginningOfTime = new DateTime();

        if (beginningOfTime.ToString().Equals(value.ToString()))
            return "";
        else
            return value.ToString();
    }

    /// <summary>
    /// Dates the input generator.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    protected DateTime DateInputGenerator(string value)
    {
        DateTime parsedDate;

        if (DateTime.TryParse(value, out parsedDate))
            return parsedDate;
        else
            return new DateTime();
    }
}

Here is the WCF Interface:

[ServiceContract]
public interface IIndicatorService
{
    [OperationContract]
    [WebGet(UriTemplate = "/GetIndicators/{SpeedId}", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
    List<IndicatorGridLineItem> GetIndicators(string SpeedId);

    [OperationContract]
    [WebInvoke(UriTemplate = "/UpdateIndicators", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]  
    void UpdateIndicators(string Indicators);
}

Finally, here is the code for my Update Implementation inside the WCF Service:

    public void UpdateIndicators(string Indicators)
    {
        var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        IEnumerable<IndicatorGridLineItem> foos = serializer.Deserialize<IEnumerable<IndicatorGridLineItem>>(Indicators);

    }

When I set a breakpoint inside this function here is what I am seeing for

string Indicators ="Indicators=%5B%7B%22ActualFinish%22%3Anull%2C%22IndicatorName%22%3A%22Ownership%22%2C%22IndicatorUID%22%3A%220ac1eb81-d44c-4b6a-9c3b-043537805cc7%22%2C%22LastUpdatedBy%22%3Anull%2C%22LastUpdatedDate%22%3Anull%2C%22POPL3Commit%22%3A%222013-11-26T08%3A00%3A00.000Z%22%2C%22PlanOfRecord%22%3Anull%2C%22Trend%22%3Anull%2C%22TrendColor%22%3Anull%7D%5D"

When the line IEnumerable foos = serializer.Deserialize>(Indicators); is executed while debugging I get the following ArgumentException: Invalid JSON primitive: Indicators.System.ArgumentException was unhandled by user code

HResult=-2147024809
Message=Invalid JSON primitive: Indicators.
Source=System.Web.Extensions
StackTrace:
   at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()
   at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)
   at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)
   at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)
   at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)
   at PDD_Web_UI.IndicatorService.UpdateIndicators(String Indicators) in c:\TFS-Newest\PCSO CSE\PDD Web UI\IndicatorService.svc.cs:line 23
   at SyncInvokeUpdateIndicators(Object , Object[] , Object[] )
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
InnerException: 

Also please note, I tried to modify the WCF Service parameter to use IEnumerable Indicators but was unable to hit the break point inside of my UpdateIndicators method at all without string Indicators as my parameter.

回答1:

Your JSON is being URL encoded - you should set data to an already serialized string:

transport: {
    read: {
        url: "IndicatorService.svc/GetIndicators/" + speedID
    },
    update: function (options) {
        $.ajax({
            type: "POST",
            url: "IndicatorService.svc/UpdateIndicators",
            dataType: "json",
            contentType: "application/json",
            data: kendo.stringify({ Indicators: options.data.models }),
            success: function (result) {
                options.success(result);
            },
            error: function (result) {
                options.error(result);
            }
        });
    }
},

Additionally, you should be able to use

void UpdateIndicators(List<Indicator> Indicators);

instead of

void UpdateIndicators(string Indicators);

on the server-side; I believe WCF will deserialize that for you.



回答2:

Ok I figured it out.

JS Code:

       $(document).ready(function () {
           $("#grid").kendoGrid({
               dataSource:
                   {
                   type: "json",
                   transport:
                        {
                            read: function (options) {
                                $.ajax({
                                    url: "IndicatorService.svc/GetIndicators/" + speedID,
                                    dataType: "json",
                                    success: function (result) {
                                        options.success(result);
                                    }
                                });

                            },

                            update: function(options) {
                                $.ajax({
                                    type: "POST",
                                    url: "IndicatorService.svc/UpdateIndicators",
                                    dataType: "json",
                                    contentType: "application/json",
                                    data: JSON.stringify( options.data.models ),
                                    success: function (result) {
                                        // notify the data source that the request succeeded
                                        options.success(result);
                                    },
                                    error: function (result) {
                                        // notify the data source that the request failed
                                        options.error(result);
                                    }
                                });
                            }



                        },
                   batch: true,
                   schema: {
                       type: 'json',
                       model: {
                           id: "IndicatorUID",
                           fields: {
                               IndicatorUID: { type: "guid" },
                               IndicatorName: { type: "string" },
                               LastUpdatedBy: { type: "string" },
                               LastUpdatedDate: { type: "date" },
                               POPL3Commit: { type: "date" },
                               ActualFinish: { type: "date" },
                               PlanOfRecord: { type: "date" },
                               Trend: { type: "date" }

                           }
                       }
                   },
                   pageSize: 10

               },
               height: 430,
               filterable: true,
               sortable: true,
               pageable: true,
               toolbar: ["create", "save", "cancel"],
               editable: true,

               columns: [
                   {
                       field: "IndicatorName",
                       title: "IndicatorName",
                       width: 120
                   },
                   {
                       field: "POPL3Commit",
                       title: "POPL3Commit",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "PlanOfRecord",
                       title: "PlanOfRecord",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "Trend",
                       title: "Trend",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "ActualFinish",
                       title: "ActualFinish",
                       format: "{0:MM/dd/yyyy}",
                       width: 120
                   },
                   {
                       field: "LastUpdatedBy",
                       title: "LastUpdatedBy",
                       width: 120
                   },
                   {
                       field: "LastUpdatedDate",
                       title: "LastUpdatedDate",
                       width: 120
                   }
               ]
           });
       });

WCF Service:

    public void UpdateIndicators(List<IndicatorGridLineItem> Indicators)

The answer came to me after working with your answer and the answer shown here: https://stackoverflow.com/a/6323528/1710400