【问题标题】:Service Stack response DTO with specific data inside JSON arrays带有 JSON 数组中特定数据的服务堆栈响应 DTO
【发布时间】:2013-04-17 16:05:57
【问题描述】:

我正在为返回 JSON 数据的服务建模我的响应 DTO:

{
    "response":
    {
        "metadataA" : "useless info a",
        "metadataB" : "useless info b",
        "metadataC" : "useless info c",
        ...
        "metadataZ" : "useless info z",
        "results" :
        [
            {
                "resultmetadataA" : "useless info a",
                "resultmetadataB" : "useless info b",
                "resultId": "a",
                "resultName": "A"
            },
            {
                "resultmetadataA" : "useless info a",
                "resultmetadataB" : "useless info b",
                "resultId": "b",
                "resultName": "B"
            }

        ]
    }
}

显然,我只希望我的 DTO 有一个带有 id 和名称的结果列表,如下所示:

class Response
{
    public List<Result> Results { get; set; }
}

class Result
{
    public string Id  { get; set; }
    public string Name  { get; set; }
}

是否有一些属性属性可以告诉服务堆栈 id 和 name 值的“路径”?


编辑 1

我正在尝试使用 ServiceStack.DataAnnotations 中的一些属性,但没有成功。 尝试在 ResultsAlias 中使用 CompositeIndex(false, "response", "results") Results 属性,但结果仍然为空.

请帮忙!

编辑 2

还尝试在响应中使用[DataContract] 并在属性上尝试[DataMember(Name = Id/Name)]直接解析这些数据,但它似乎不起作用。

【问题讨论】:

    标签: c# servicestack dto


    【解决方案1】:

    你可以使用字典:

    public class ResponseDTO
    {
        public List<Dictionary<string, string>> Results { get; set; }
    }
    

    【讨论】:

    • 真的很好!但是没有办法得到更强类型的东西?!
    • 使用你的方法,我可以在“response”中得到字符串对,但是当将属性名称从Response更改为Results时,我得到一个空字典。
    • 我看不出将属性名称从Response 重命名为Results 与这里的问题有什么关系。如果你使用Results,你会得到Results: [...],如果你使用Response,你会得到Response: [...]。如果你想得到results: [...](注意小写的r),你可以用[DataMember(Name = "results")]属性修饰你的字典属性,用[DataContract]修饰你的响应DTO来完全控制JSON序列化。跨度>
    【解决方案2】:

    从您的 JSON 开始是无效的 "response": [ 不能是数组文字,但包含对象属性。

    如何调试序列化问题

    目标是让您的架构与 JSON 的形状相匹配。不要试图猜测形状应该是什么,养成推断形状的习惯,尝试看看哪些属性会被序列化。如果没有属性被序列化,则执行相反的操作并填充和序列化您的 POCO 以查看它们预期的形状,然后将这些形状与原始 JSON 进行比较以查看它们的不同之处。见this answer for other tips on debugging serialization issues

    var json = @"{
        ""response"":
        {
            ""metadataA"" : ""useless info a"",
            ""metadataB"" : ""useless info b"",
            ""metadataC"" : ""useless info c"",
            ""metadataZ"" : ""useless info z"",
            ""results"" :
            [
                {
                    ""resultmetadataA"" : ""useless info a"",
                    ""resultmetadataB"" : ""useless info b"",
                    ""resultId"": ""a"",
                    ""resultName"": ""A""
                },
                {
                    ""resultmetadataA"" : ""useless info a"",
                    ""resultmetadataB"" : ""useless info b"",
                    ""resultId"": ""b"",
                    ""resultName"": ""B""
                }
    
            ]
        }
    }";
    

    从上述 JSON 中推断出的类型:

    public class MetadataResponse
    {
        public Response Response { get; set; }
    }
    
    public class Response
    {
        public string MetadataA { get; set; }
        public string MetadataB { get; set; }
        public string MetadataC { get; set; }
        public string MetadataZ { get; set; }
        public List<Result> Results { get; set; }
    }
    
    public class Result
    {
        public string ResultmetadataA { get; set; }
        public string ResultmetadataB { get; set; }
        public string ResultId { get; set; }
        public string ResultName { get; set; }
    }
    

    使用上述类型测试 JSON 序列化:

    var dto = json.FromJson<MetadataResponse>();
    dto.PrintDump();
    

    输出:

    {
        Response: 
        {
            MetadataA: useless info a,
            MetadataB: useless info b,
            MetadataC: useless info c,
            MetadataZ: useless info z,
            Results: 
            [
                {
                    ResultmetadataA: useless info a,
                    ResultmetadataB: useless info b,
                    ResultId: a,
                    ResultName: A
                },
                {
                    ResultmetadataA: useless info a,
                    ResultmetadataB: useless info b,
                    ResultId: b,
                    ResultName: B
                }
            ]
        }
    }
    

    【讨论】:

    • @cvsguimaraes 将其映射到您想要的任何内容,例如:dto.Results.ConvertAll(x =&gt; new MyResult { ... }); 您也可以使用 DataMember 属性指定[DataMember(Name="resultId")] public string Id { getl set; },或parse it dynamically instead
    • @cvsguimaraes 你删除了你的评论??
    • 是的,因为在调试序列化之前问了其他问题而感到羞耻。我会试试最后一个,谢谢!
    • 看看我的回答,它可以更好地解释我想要实现的目标。没有其他选项的运气,我已经按照dto.Results.ConvertAll(x =&gt; new MyResult { ... }); 的建议进行了映射,但首先我需要定义公共响应结构。欢迎对我的解决方案进行任何考虑。再次感谢所有帮助伙伴!
    【解决方案3】:

    毕竟,我找不到为复杂响应建模简单 DTO 的方法,无论如何感谢所有答案。

    嗯,很遗憾我的 POCO 的结构依赖于 JSON 响应结构。但是,我可以抽象出响应结构并让我的所有 DTO 一次处理它。

    考虑到我的问题中类似的 JSON 结构:

    {
        "response":
        {
            ...,
            "results":
            [
                {
                    "resourceType": "letter" ,
                    "resources": ["a", "b", "c", ...]
                },
                {
                    "resourceType": "number" ,
                    "resources": ["1", "2", "3", ...]
                },
                ...
            ]    
        }
    }
    

    我抽象了常用的响应结构:

    enum ResourceKind
    {
        Letter,
        Number
    }
    
    public class BaseResponse
    {
        public ResponseContent Response
        {
            get;
            set;
        }
    }
    
    public class ResponseContent
    {
        public List<ResultContent> Results
        {
            get;
            set;
        }
    }
    
    public class ResultContent
    {
        public ResourceKind Kind
        {
            get;
            set;
        }
    
        public List<string> Resources
        {
            get;
            set;
        }
    }
    

    最后得到了一个(几十个)特定服务器响应的简化实现:

    public class SpecificResponse : BaseResponse
    {
        public IEnumerable<SpecificResult> Results
        {
            get
            {
                foreach(ResultContent result in Response.Results)
                {
                    SpecificResult newSpecificResult = new SpecificResult();
                    newSpecificResult.Kind = result.Kind;
                    newSpecificResult.Resources = result.Resources;
                    yield return newCategory;
                }
    
                yield break;
            }
        }
    }
    

    我仍在寻找更好的东西,但现在这是我的解决方案。

    【讨论】:

    • 很遗憾您必须将 POCO 映射到 JSON 结构?这就是序列化程序的全部目的。 Use dynamic 如果您不想使用类型来动态解析。
    • @mythz 是的,想象一个世界,我们可以只使用想要的数据来定义我们的 POCO如果它位于响应的根部或在 n 个数组内,则无所谓第三方服务返回的任何垃圾......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    相关资源
    最近更新 更多