Web API介面回傳實作類別集合的姿勢了解

Web API介面回傳實作類別集合的姿勢了解

.NET Web API介面回傳基底類別列表,測試介面只回傳了基底類別的屬性,實作類別的屬性怎麼回傳呢?

最後更新 2023/3/19 下午8:55
沙漠尽头的狼
預計閱讀 3 分鐘
分類
ASP.NET Core
標籤
.NET C# ASP.NET Core Web API

大家好,我是沙漠盡頭的狼。

一. 問題描述

如下圖,定義兩個子類別 Student 和 Employ,都繼承自抽象類別 PersonBase:

public abstract class PersonBase
{
    public string Name { get; set; }

    protected PersonBase(string name)
    {
        Name = name;
    }
}

public class Student : PersonBase
{
    public string Number { get; set; }

    public Student(string name, string number) : base(name)
    {
        Number = number;
    }
}

public class Employ : PersonBase
{
    public string CompanyName { get; set; }

    public Employ(string name, string companyName) : base(name)
    {
        CompanyName = companyName;
    }
}

新增 Web API 介面傳回基底類別集合:

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpGet(Name = "GetDetails")]
    public IEnumerable<PersonBase> Get()
    {
        return new List<PersonBase>()
        {
            new Student("學生A", "學生號01"),
            new Employ("職員01", "百度")
        };
    }
}

介面回傳值:

[
  {
    "name": "學生A"
  },
  {
    "name": "職員01"
  }
]

發現問題了嗎?Student 類別和 Employ 類別實例的擴充屬性(Student 的 Number 屬性,Employ 的 CompanyName 屬性)都未被序列化顯示,那麼要怎麼序列化子類別的所有屬性呢?

二、實現類別的所有屬性序列化

參考微軟文件《如何使用 System.Text.Json 序列化衍生類別的屬性》,有兩種實作方式站長覺得比較簡單。

2.1、.NET 7 之前的實作方式

在 .NET 7 之前的版本中,System.Text.Json 不支援多型類型層次結構的序列化。例如,如果介面的回傳值類型為介面或抽象類別集合,那麼即使執行時期類型有其他屬性,也只會序列化對介面或抽象類別定義的屬性。

解決方案:將介面回傳值由 IEnumerable<PersonBase> 改為 object,介面實作的 List<PersonBase> 改為 List<object>

[HttpGet(Name = "GetDetails")]
public object Get()
{
    return new List<object>()
    {
        new Student("學生A", "學生號01"),
        new Employ("職員01", "百度")
    };
}

修改後,介面成功回傳詳細 JSON 資訊:

[
  {
    "number": "學生號01",
    "name": "學生A"
  },
  {
    "companyName": "百度",
    "name": "職員01"
  }
]

原理: 改為 Object 後,預設就是對實作類別進行序列化了,改之前 System.Text.Json 只認識實作類別的爸爸。

2.2、.NET 7 及以後的實作方式

從 .NET 7 開始,System.Text.Json 支援使用特性標註的多型類型層次結構序列化和反序列化。

我們將介面恢復,在抽象類別上添加特性,標明基底類別序列化時需要對應的子類別類型:

[JsonDerivedType(typeof(Student))]
[JsonDerivedType(typeof(Employ))]
public abstract class PersonBase

問題解決,介面回傳值同上。

文件關於 JsonDerivedTypeAttribute 的描述:當放置在類型宣告中時,則指示應選擇指定的子類型進行多型序列化。它也公開用於指定類型鑑別器的功能。

三、總結

上面兩種方式看 .NET 版本選擇,第二種方式需要您明確知道子類別類型,詳細使用請看微軟文件:如何使用 System.Text.Json 序列化衍生類別的屬性

如果您有更好的方式歡迎留言探討。

  • 微信技術交流群:添加微信(codewf)備註「入群」
  • QQ技術交流群:771992300。

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2022/4/13

ASP.NET Core WebApi 回傳結果統一包裝實務

關於 WebApi 統一結果回傳的時候,讓我也有了更進一步的思考,首先是如何能更好的限制回傳統一的格式,其次是關於結果的包裝一定是更簡單更強大。在不斷的思考和完善中,終於有了初步的成果,便分享出來,學無止境思考便無止境,希望以此能與君共勉。

繼續閱讀