无法通过 GET 反序列化数组

Posted

技术标签:

【中文标题】无法通过 GET 反序列化数组【英文标题】:Unable to deserialize array via GET 【发布时间】:2014-09-10 00:49:48 【问题描述】:

我正在使用 Kendo UI 的 DataSource 将排序信息发送到我的 ServiceStack 服务。我知道这个has been addressed 如果您使用的是POST,但我想坚持RESTful 设计,所以请求动词需要是GET。我正在使用这个 sn-p 进行测试:

var dataSource = new kendo.data.DataSource(
        serverSorting: true,
        sort: [ field: "ProductName", dir: "desc" ,
                field: "Category", dir: "asc"],

        serverPaging: true,
        page: 2,
        pageSize: 5,

        transport: 

            read: 
                url: "/products",
                dataType: "json",
                contentType: "application/json",
                dataType: "jsonp"
            ,

            parameterMap: function (data, type) 
                //return kendo.stringify(data);
                //return JSON.stringify(data);
                //return $.param(data, true);
                //data.sort = kendo.stringify(data.sort);
                return data;
            
        
    );

    dataSource.fetch(function () 
        console.log(dataSource.view());
    );

排序参数变成一个锯齿状数组,如:

sort[0][field]: ProductName
sort[0][dir]: desc
sort[1][field]: Category
sort[1][dir]: asc

我的请求 DTO 是:

    public class SortTerm

    public string field  get; set; 
    public string dir  get; set; 


public class KendoQuery


    public List<SortTerm> Sort  get; set; 

    public int Skip  get; set; 
    public int Take  get; set; 
    public int Page  get; set; 
    public int PageSize  get; set; 

所有简单的参数都被反序列化了,但是我到底如何才能在客户端或服务器端转换 Sort 属性以使其正确填充?

请注意,我在 parameterMap 函数中尝试了各种序列化技术,但我完全被难住了。

编辑

所以这一切都归结为:当 jQuery 仔细地将我的请求重新排列成锯齿状数组时,如何通过 $.get() 将对象数组传递给 ServiceStack 服务?这有点像请求过滤器,但我不得不想象它之前已经解决了 **GET** 请求。

【问题讨论】:

【参考方案1】:

您不能将复杂的数据结构(例如锯齿状排序数组的数据结构)与使用标准技术的 GET 请求一起使用,因为 JSON GET 请求仅支持简单变量,因为这些变量可以转换为查询字符串中的请求参数.因此,对于简单参数 ?Page=2&amp;PageSize=5 ...,请求将正确形成,但对于 sort[0][field],这不能指定为查询字符串请求参数。

但是,如果您在哪里使用datasource.transport.parameterMap 对搜索条件对象进行字符串化,以便可以将其作为参数传递,然后在服务器上进行转换,则可以解决此问题。

parameterMap: function (data, type) 
    // Convert the search criteria to a JSON string and store it on value sortJson
    data.sortJson = JSON.stringify(data.sort);

    // Remove the sort value, as this will be provided by sortJson
    delete data.sort;

    // Return the data
    return data

在服务器上,您需要处理将 JSON 字符串转换为 List&lt;SortTerm&gt;

public class KendoQuery


    List<SortTerm> sort;
    public List<SortTerm> Sort 
         get 
             // Handles deserialising the SortJson value 
             if(sort == null)
                 sort = ServiceStack.JsonSerializer.DeserializeFromString<List<SortTerm>>(SortJson);
             return sort;
         
    

    public string SortJson  get; set;  
    public int Skip  get; set; 
    public int Take  get; set; 
    public int Page  get; set; 
    public int PageSize  get; set; 

我希望这会有所帮助。

【讨论】:

正如你所说,我想出来的总体原因是 GET 无法合理地传递复杂的数据结构。虽然我说客户端或服务器端修复都可以,但我更喜欢服务器端来保持客户端代码干净,并且与后端无关。我已经在下面的答案中发布了我的代码。 @jklemmack 是的,尽可能保持客户端清洁是合理的,因此您的解决方案看起来也很合适(+1)。【参考方案2】:

Scott 上面的答案是正确的,但这是我更以服务器为中心的解决方案。基本上,我从查询字符串中手动重建 SortTerm 对象。这可以扩展到其他特定于 Kendo 的参数,例如过滤器和组。

客户端代码:

<html>
<head>
    <meta charset="utf-8">
    <title>Kendo UI Snippet</title>

    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://cdn.kendostatic.com/2014.1.528/js/kendo.all.min.js"></script>
</head>
<body>
    <script>
        var dataSource = new kendo.data.DataSource(
            serverSorting: true,
            sort: [ field: "ProductName", dir: "desc" ,
                    field: "Category", dir: "asc" ],

            serverPaging: true,
            page: 2,
            pageSize: 5,

            transport: 
                read: 
                    url: "/products",
                    dataType: "json"
                
            
        );

        dataSource.fetch(function () 
            console.log(dataSource.view());
        );
    </script>
</body>
</html>

服务器代码(在 AppHost 实现中)

this.GlobalRequestFilters.Add((req, resp, dto) =>

    if (dto is KendoQueryBase)
    
        KendoQueryBase qb = dto as KendoQueryBase;
        if (qb.Sort == null) qb.Sort = new List<SortTerm>();
        Dictionary<string, string> qs = req.QueryString.ToDictionary();
        var i = 0;
        while (qs.ContainsKey("sort[0][field]".Fmt(i)))
        
            qb.Sort.Add(new SortTerm()
            
                field = qs["sort[0][field]".Fmt(i)],
                dir = qs["sort[0][dir]".Fmt(i)]
            );
            i++;
        
    
);

【讨论】:

以上是关于无法通过 GET 反序列化数组的主要内容,如果未能解决你的问题,请参考以下文章

使用 Unity JsonUtility 反序列化 JSON 数组无法获取序列化值

使用JSON.NET反序列化json - 无法反序列化,因为类型需要一个JSON数组c#

使用gson,改进将json数组反序列化为模型的正确方法

无法将 JSON 数组(例如 [1,2,3])反序列化为类型 ' ',因为类型需要 JSON 对象(例如 "name":"value")才能正确反序列化

无法将 JSON 数组(例如 [1,2,3])反序列化为类型 ' ',因为类型需要 JSON 对象(例如 "name":"value")才能正确反序列化

无法反序列化 xml 数组以列出 web api 模型 c#