亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

僅從 API 返回對象的屬性子集

僅從 API 返回對象的屬性子集

C#
BIG陽 2022-08-20 15:58:27
假設我有一個數據庫,其中存儲了此結構的用戶詳細信息:public class User{    public string UserId { get; set; }    public string Name { get; set; }    public string Email { get; set; }    public string PasswordHash { get; set; }}我有一個數據訪問層,它包含GetById()等方法,并返回一個User對象。但是,假設我有一個API,它需要返回用戶詳細信息,但不是敏感部分,例如PasswordHash。我可以從數據庫中獲取用戶,但隨后我需要刪除某些字段。什么是“正確”的方法?我已經想到了幾種方法來處理這個問題,其中大部分涉及將User類拆分為包含非敏感數據的BaseClass和包含我希望保密的屬性的派生類,然后在返回之前將對象轉換或映射到BaseClass,但是這感覺很笨拙和骯臟。感覺這應該是一個相對常見的情況,所以我錯過了一個簡單的方法來處理它嗎?我正在使用 ASP.Net 核心和MongoDB,但我想這更像是一個普遍的問題。
查看完整描述

4 回答

?
長風秋雁

TA貢獻1757條經驗 獲得超7個贊

出于我的目的,似乎最整潔的解決方案是這樣的:


將 User 類拆分為基類和派生類,并添加構造函數以復制必填字段:


public class User

{

    public User() { }


    public User(UserDetails user)

    {

        this.UserId = user.UserId;

        this.Name = user.Name;

        this.Email = user.Email;

    }


    public string UserId { get; set; }

    public string Name { get; set; }

    public string Email { get; set; }

}


public class UserDetails : User

{

    public string PasswordHash { get; set; }

}

數據訪問類將返回一個 UserDetails 對象,然后可以在返回之前對其進行轉換:


UserDetails userDetails = _dataAccess.GetUser();

User userToReturn = new User(userDetails);

也可以按照 Daniel 的建議使用自動映射器而不是構造函數方法來完成。我不喜歡這樣做,因此我問這個問題,但這似乎是最整潔的解決方案,需要最少的重復。


查看完整回答
反對 回復 2022-08-20
?
Helenr

TA貢獻1780條經驗 獲得超4個贊

有兩種方法可以做到這一點:

  1. 使用相同的類,并且僅填充要發送的屬性。這樣做的問題是,值類型將具有默認值(屬性將作為 發送,如果這可能不準確)。int0

  2. 對要發送到客戶端的數據使用其他類。這基本上就是丹尼爾在評論中得到的 - 你有一個不同的模型,由客戶“查看”。

第二種選擇是最常見的。如果您使用的是 Linq,則可以使用以下命令映射值:Select()

users.Select(u => new UserModel { Name = u.Name, Email = u.Email });

基本類型不會像您希望的那樣工作。如果將派生類型強制轉換為其父類型并對其進行序列化,它仍會序列化派生類型的屬性。

以這個為例:

public class UserBase {

    public string Name { get; set; }

    public string Email { get; set; }

}


public class User : UserBase {

    public string UserId { get; set; }

    public string PasswordHash { get; set; }

}


var user = new User() {

    UserId = "Secret",

    PasswordHash = "Secret",

    Name = "Me",

    Email = "something"

};


var serialized = JsonConvert.SerializeObject((UserBase) user);

請注意,序列化時強制轉換。即便如此,結果是:


{

    "UserId": "Secret",

    "PasswordHash": "Secret",

    "Name": "Me",

    "Email": "something"

}

它仍然序列化了該類型的屬性,即使它被強制轉換為 。UserUserBase


查看完整回答
反對 回復 2022-08-20
?
qq_笑_17

TA貢獻1818條經驗 獲得超7個贊

如果要忽略該屬性,只需在模型中添加忽略 annotation,就像這樣,當模型序列化時,它將跳過該屬性。


[JsonIgnore] 

public string PasswordHash { get; set; }

如果你想在運行時忽略(這意味著動態).Newtonsoft.Json中有一個構建函數可用


public class User

{

    public string UserId { get; set; }

    public string Name { get; set; }

    public string Email { get; set; }

    public string PasswordHash { get; set; }

    //FYI ShouldSerialize_PROPERTY_NAME_HERE()

   public bool ShouldSerializePasswordHash()

    {

        // use the condtion when it will be serlized

        return (PasswordHash != this);

    }

}

它被稱為“條件屬性序列化”,文檔可以在這里找到。


查看完整回答
反對 回復 2022-08-20
?
皈依舞

TA貢獻1851條經驗 獲得超3個贊

問題是你看錯了。API 即使直接與特定的數據庫實體一起工作,也不會處理實體。這里有一個關注點分離問題。您的 API 正在處理用戶實體的表示形式。實體類本身是數據庫的函數。它上面有一些只對數據庫重要的東西,重要的是,它上面的東西對你的API無關緊要。嘗試使用一個可以滿足多個不同應用程序的類是愚蠢的,并且只會導致具有嵌套依賴項的代碼變脆。

更重要的是,您將如何與此 API 交互?也就是說,如果您的API直接公開您的實體,那么使用此API的任何代碼都必須依賴于您的數據層以便它可以訪問,或者它必須實現自己的類來表示,并希望它與API實際想要的相匹配。UserUserUser

現在想象一下替代方案。創建一個“通用”類庫,該類庫將在 API 和任何客戶端之間共享。在該庫中,您可以定義類似 .您的 API 僅綁定到/從 綁定,并將其來回映射到 ?,F在,您已經完全隔離了數據層??蛻舳酥恢溃ㄒ挥|及數據層的是你的API。當然,現在您可以限制向API客戶端公開的信息,只需通過構建方式即可。更好的是,如果您的應用程序需求發生變化,則可以更改,而不會像每個消費客戶端的API沖突一樣螺旋式上升。您只需修復API,客戶端就會在不知情的情況下繼續。如果確實需要進行重大更改,可以執行某些操作,例如創建類以及新版本的 API。如果不創建一個全新的表,就無法創建一個全新的表,然后這會在標識中引發沖突。UserResourceUserResourceUserUserResourceUserUserResourceUserUserResource2User2

長話短說,使用 API 的正確方法是始終使用單獨的 DTO 類,甚至多個 DTO 類。API 永遠不應該直接使用實體類,否則你只會感到痛苦。


查看完整回答
反對 回復 2022-08-20
  • 4 回答
  • 0 關注
  • 125 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號