【问题标题】:Supply additional information with some specific items in a list为列表中的某些特定项目提供附加信息
【发布时间】:2019-01-29 14:01:26
【问题描述】:

假设我有一个包含如下属性的类:

ListOfObjectA;

对象A定义如下:

Class ObjectA:
Prop a
Prop b

ListOfObjectA(由 API 端点作为 DTO 返回)将在 UI 中呈现。

在某些情况下,列表中的特定 ObjectA 实例需要提供额外的支持信息(假设另一个对象 SubObjectA(一种复杂类型),这对于列表中的其他项目不常见),即n+1 例。

我正在尝试了解返回此信息的最佳方式,而不会让 DTO 被不必要的信息阻塞。

一种选择是将 SubObjectx 包含在 ObjectA 类本身中 - 当它为 null 或为空时,不要打扰以其他方式渲染它。我们会在需要的地方以编程方式填充它...

第二个选项可能是向 ObjectA 类添加一个 url 属性 - url 可以是空的,也可以指向一个端点以获取更多信息,然后可以呈现响应。

我个人反对第一个选项是 ListOfObjectA 中的每个对象将始终包含不相关的信息。我更喜欢第二个选项,因为它包含一个字符串(端点),即if 具有从何处获取子对象的值。但这也意味着 API 的客户端现在将编写一些逻辑来在需要时访问这些端点。

我想知道是否还有其他更好的方法可以做到这一点?

如果我解释情况的尝试不是很好,请问我一个问题。

【问题讨论】:

    标签: c# api asp.net-core dto class-design


    【解决方案1】:

    无论您是从请求正文进行 JSON 的自动模型绑定还是手动使用 JsonConvert 之类的东西来创建模型,您的 DTO 类都需要具有所有可能的属性。根据某些特定数据的存在或缺乏,没有真正的方法可以从同一组数据中实例化不同类型的对象。也就是说,您可以创建一个自定义模型绑定器和一些自定义 JSON 解析器来完成这项工作,但是对于主要是装饰性的东西所涉及的工作量并不值得投资。

    不管怎样,这只是 DTO 类本身的问题。您可以利用 JSON.NET 中的东西,例如 JsonIgnore 属性和 NullValueHandlingDefaultValueHandling 枚举来隐藏实际 JSON 中的成员,如果这是您最关心的问题。例如:

    public class ObjectA:
    {
        public string A { get; set; }
        public string B { get; set; }
    
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string C { get; set; }
    }
    

    然后,当您序列化对象时,如果未设置 C 属性,您将获得如下 JSON:

    {
        "a" : "foo",
        "b" : "bar"
    }
    

    如果设置好了,你会得到:

    {
        "a" : "foo",
        "b" : "bar",
        "c" : "baz"
    }
    

    除此之外,我认为您最好的选择是在必要时请求额外数据的链接。这实际上是一件非常 REST 的事情。它本质上是HATEOAS。但是,它也非常健谈。这将需要提出更多请求,特别是如果您必须为多个项目执行此操作。它本质上是应用于 API 的 N+1 数据库查询问题。

    【讨论】:

    • 哦,这太棒了!谢谢!我也同意 URL 方法,但我们的客户对使用它们提取附加数据犹豫不决——原因之一是“非常健谈”。
    【解决方案2】:

    您可以使用List<anonymous_objects>

        var DTO = new List
        {  
           new {City = "Chicago", Code = "114"},
           new {City="Washington"},
           new {City="London", Code = "2"}
       }
    

    等等。但是有一个小问题:您需要使用反射从项目中获取数据:

     var city = DTO[0].GetType().GetProperty(nameof(DTO[0].City)).GetValue(DTO[0]);
    

    另外,我想(我没有检查)你可以使用List<dynamic>。都一样,但你会写new List<dynamic>,你不需要使用GetType和所有这些东西。只需写DTO[0].City。试试这个:)

    【讨论】:

    • 您好,感谢您花时间阅读我的问题。这会起作用,但 imo 你最终会得到非常冗长的代码。对反序列化的客户也有更多的工作。
    猜你喜欢
    • 2015-12-13
    • 1970-01-01
    • 2011-01-30
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多