3

我有一个 DTO 对象,它上面有一个 JsonObject (Data) 属性,以便我可以存储序列化的对象。

我在下面包含了服务堆栈服务。

using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace BuffaloInspection.WebApi.Services
{
    [Route("/_layouts/api/test")]
    public class ItemDTO
    {
        public int ID { get; set; }
        public string Title { get; set; }
        public JsonObject Data { get; set; }
        public string DataStr { get; set; }
    }

    public class TestService : Service
    {
        public ItemDTO POST(ItemDTO request)
        {
            var response = new ItemDTO();

            response.ID = request.ID;
            response.Title = request.Title;

            //Failing
            response.DataStr = request.Data.ToJson();
            response.Data = JsonObject.Parse(response.DataStr);

            return response;
        }
    }
}

我正在使用以下 html 页面来调用上述服务。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="SSTest">
<head>
    <title>Service Stack Test</title>
</head>
<body>
    <div ng-controller="TestCtrl">
        <div>ID:<input type="text" name="id" ng-model="item.ID" value="1" /></div>
        <div>Title:<input type="text" name="title" ng-model="item.Title" value="Test" /></div>
        <div>Length:<input type="text" name="length" ng-model="item.Data.Length" value="10" /></div>
        <div>
            <button type="button" value="save" ng-click="save(item)">Save</button>
        </div>
    </div>

    <script type="text/javascript" src="components/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="components/angular/angular.min.js"></script>
    <script type="text/javascript">
        'use strict';
        var app = angular.module('SSTest', []);

        app.controller('TestCtrl', TestCtrl);
        function TestCtrl($scope, $http) {
            $scope.item = {
                ID: 1,
                Title: 'Test "',
                Data: {
                    Length: '10 "'
                }
            };

            $scope.save = function (data) {
                console.log('before:');
                console.log(data);
                $http.post("http://localhost:8001/_layouts/api/test/", data).then(function (result) {
                    console.log('after: ');
                    console.log(result.data);
                    $scope.item = result.data;
                });
            }
        }

    </script>
</body>
</html>

我加载页面并点击保存。此时客户端对象如下: {"ID":1,"Title":"Test \"","Data":{"Length":"10 \""}}

当代码到达//Failing上面注释的服务器代码行时,问题是request.Data对象包含一个已经转义的字段,ToJson()调用再次转义,以便当我检索数据时得到10\\\"

request.Data 是具有以下信息的 JSON 对象:[0] {[Length, 10 \"]} response.DataStr 现在包含{"Length":"10 \\\""}

回到客户端我的返回对象现在有额外的转义

有谁知道如何确保特殊字符不会被双重转义?

4

2 回答 2

2

我们有完全相同的情况,我们使用嵌套的 JsonObject 来获得动态对象(尽管受 Json-Schema 限制)。

在我们使用 OrmLite 之前,一切(序列化/反序列化)都可以很好地工作。当 TypeSerializer 反序列化存储的 dto 时,它会为嵌套 JsonObject 中的字符串值添加引号,因此当 Dto 反序列化到线路时,它会获得额外的 \"。

为了解决这个问题,我们和您一样,有另一个 dto 用于存储目的,但使用的是:

toStore.DataStr = request.Data.SerializeToString();
response.Data = JsonObject.Parse(toStore.DataStr);

这适用于我们的 Service Stack 3.9.66

于 2013-11-07T12:35:25.577 回答
1

ServiceStack.Text 项目在使用转义字符进行序列化和反序列化方面没有已知问题。请参阅以下通过的单元测试

ServiceStack.Text / 测试 / ServiceStack.Text.Tests / JsonTests / EscapedCharsTests.cs

更具体地说,如果我运行以下代码,我会得到预期的输出。看起来您在此过程中正在做的事情使序列化器感到困惑。

var o = new JsonObject();
o.Add("Length", "10\"");
Debug.WriteLine(o.ToJson());
// Outputs   {"Length":"10\""}

更新:Estyn 的评论帮助我再次思考这个问题。 看看这个扩展方法string Get(this Dictionary map, string key)

该测试现在将通过:

var o1 = new JsonObject {{"Length", "10\""}};
var json = o1.ToJson();

var o2 = json.FromJson<JsonObject>();
Assert.AreEqual(o2.Get("Length"), "10\"");

如果您使用 Get 扩展方法,它将取消额外的转义。您可以单步执行序列化程序,然后深入了解代码。由于序列化嵌入式 JSON 的奇怪性质,我很难说它是否是一个错误。

于 2013-08-29T13:42:23.350 回答