受保护属性的 WebAPI 反序列化为空

Posted

技术标签:

【中文标题】受保护属性的 WebAPI 反序列化为空【英文标题】:WebAPI deserialization of a protected property is null 【发布时间】:2020-07-21 00:39:02 【问题描述】:

我的解决方案有一个 WebAPI 项目(.net core 3.1、Microsoft.AspNetCore.Mvc)和一个定义数据结构的(.Net Standard 2.1)类库。 我的控制器使用单个参数发布一个帖子,该参数大部分正确地反序列化


public class apiRequest

    public RequestData TheData  get; set; 
    public Options Options  get; set; 
    public apiRequest()  


RequestData 和子对象在 .Net Standard 2.1 类库中定义并通过 nuget 包添加


public class RequestData : IRequestData

    public int Datum get; set; 
    ...
    public List<ComplexItem> ComplexItems  get; set; 
    ...

public class ComplexItem: ItemBase, IComplexItem

    public ComplexItem() : base()  
    public ComplexItem(Pricing defaultPricing) : base(defaultPricing)  
    [JsonConstructor]
    public ComplexItem(Pricing defaultPricing, Pricing selectedPricing) : base(defaultPricing, selectedPricing)  


我遇到的问题是 defaultPricing 在到达控制器时始终为空


public class ItemBase : IItemBase

    public ItemBase ()  
    public ItemBase (Pricing defaultPricing)
    
        DefaultPricing = defaultPricing;
    
    [JsonConstructor]
    public ItemBase (Pricing defaultPricing, Pricing selectedPricing)
    
        DefaultPricing = defaultPricing;
        SelectedPricing = selectedPricing;
    

    #region Pricing
    [JsonProperty]
    protected Pricing DefaultPricing  get; set; 
    public Pricing SelectedPricing  get; set; 
    [JsonIgnore]
    protected Pricing CurrentPricing
    
        get  return SelectedPricing ?? DefaultPricing; 
        set  SelectedPricing = value; 
    
    [JsonIgnore]
    public decimal Cost  get => CurrentPricing?.Cost ?? 0; 
    [JsonIgnore]
    public decimal Price  get => CurrentPricing?.Price ?? 0; 
    #endregion


我尝试过使用 [DataContract] 和 [DataMember] 属性、JsonObject、JsonConstructor、JsonProperty 属性和 [Serializable] 属性。 (目前有关于使用什么的最佳实践吗?)

如果我从文件中读取 Json 并使用 Newtonsoft.Json.JsonConvert.DeserializeObject 它会正确反序列化并添加 Json 属性,但在控制器中仍为 null。

如果我将其公开,它也会在 API 中正确反序列化,因此它似乎不是 Pricing 类本身的问题

【问题讨论】:

【参考方案1】:

发布后,我发现了这个Question about making Newtonsoft the default 并使用MikeBeaton's 接受的解决方案与Microsoft.AspNetCore.Mvc.NewtonsoftJson 包一起工作,所以我将把它作为其他任何有此问题的人的潜在答案。仍然想知道是否有更正确的解决方案。

【讨论】:

【参考方案2】:

System.Text.Json 序列化公共属性

正如the documentation 所暗示的那样(强调我的)

默认情况下,所有(只读)公共属性都是序列化的。您可以指定要排除的属性。

我猜这是选择的设计,因为序列化对象允许该对象跨越范围的障碍,并且公共范围是唯一可以可靠假设的范围。

如果你仔细想想,这是有道理的。可以说,您定义了一个 protected 属性并序列化该对象。然后客户端将其拾取并将该文本表示反序列化为public 属性。您设计为派生类型的实现细节现在可以在修饰符定义的范围之外访问。

除了简单地指出您自己的答案,Newtonsoft 允许序列化此受保护的属性,我建议您更专注地查看您的设计以及为什么这些属性首先受到保护。这在您的 API 实现的上下文中是有意义的,但不能(不应该)假定客户端遵循您的相同继承结构(或根本支持继承)。似乎您可能想要定义一个真正的 DTO 来充当 API 响应的“形状”,并使用protected 范围来控制访问和可以跨越边界的 DTO 找到从内部类型转换的正确位置API。

【讨论】:

以上是关于受保护属性的 WebAPI 反序列化为空的主要内容,如果未能解决你的问题,请参考以下文章

WebAPI 2不反序列化List POST请求中FromBody对象的属性

将json的日期属性反序列化为LocalDate

将JSON反序列化为相对类

使用 XmlSerializer 将空 xml 属性值反序列化为可为空的 int 属性

将 JSON 命名属性反序列化为 .Net 对象

如何使用 System.Text.Json API 将流反序列化为对象