簡體   English   中英

DTO和實體是否都有輸入驗證

[英]Should DTO and Entity both have input validations

我有一個WCF層,我的域模型在這個WCF層后面。 我使用Nhibernate作為ORM工具,我所有的業務邏輯/數據訪問等都將在這個WCF層之后。

我向我的客戶揭露了DTO。 我有以下問題

1)我應該創建DTO嗎? 將實體直接暴露給wcf客戶端有什么害處,因為我的實體也會有業務邏輯方法這樣做我不得不用WCF屬性來破壞我的權利對象,我覺得這樣做不好?

2)如果我公開DTO,我應該驗證DTO以及實體。 如果我只驗證DTO,那么我沒有為我的Enitity對象提供任何輸入驗證。 這個可以嗎?

3)我應該考慮使用Schema驗證在Application Service層(WCF層)中驗證DTO嗎? 或者我應該使用文章[博客]中給出的IValidator方法: http ://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/,如Jimmy Bogard所示

有時DTO對我來說似乎是多余的,但我可以使用它來從一個或多個實體中獲取詳細信息。

我將這個服務暴露給各種客戶端,因此我的DTO將從一些基礎dto派生出具有憑證詳細信息,我會在實際的wcf方法調用之前檢查每個傳入的請求(可能使用IEndpointBehaviour和IParamInspector)


編輯

基於響應,我現在同意保留DTO層,這是一個例子,以便場景變得更加明確

假設我有一個CreateCustomer方法接受我的WCF應用服務層中的CustomerDetailsDTO,它可能由MVC應用程序調用。有一些輸入驗證,如

輸入驗證:

i)Name length should be greater than 2 but less than 50
ii) Age is mandatory and cann not be less than 18
(Different other field validations)etc 

業務驗證:

There could then be some business rules to check for dupliate customer 
based on say email or some other factor whcih i think should be part of
my Domain business logic and should reside in CustomerEntity class.

輸入驗證應該僅應用於服務接口層,因為我們從客戶端獲取DTO,或者它也應該應用於CustomerEntity

1)我應該創建DTO嗎? 將實體直接暴露給wcf客戶端有什么害處,因為我的實體也會有業務邏輯方法這樣做我不得不用WCF屬性來破壞我的權利對象,我覺得這樣做不好?

是的,SOA需要數據合同。

它們可以或多或少地形式化(CSV,JSON,XSD,WSDL,WADL甚至HTML或txt文件),但如果您無法就此類合同找到協議,則不應采用任何“服務”技術或技術(也沒有任何其他IPC的重要性)。

遠程處理是唯一試圖避免此類要求的技術。 這是一個驚人的想法,抽象,但具體來說它沒有用。

2)如果我公開DTO,我應該驗證DTO以及實體。 如果我只驗證DTO,那么我沒有為我的Enitity對象提供任何輸入驗證。 這個可以嗎?

您應該驗證“合同”,而不是業務規則。

例如,WCF DTO可能需要填充一些字段,我將在構造ArgumentNullException中使用ArgumentNullException

但是你應該記住,DTO用於傳輸數據。 如果您有一個數字字段,由於某些奇怪的原因必須作為字符串傳輸,您可以驗證它,例如阻止DTO的初始化。

3)我應該考慮使用Schema驗證在Application Service層(WCF層)中驗證DTO嗎? 或者我應該使用文章[博客]中給出的IValidator方法: http ://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/,如Jimmy Bogard所示

如果您需要域模型(這意味着您需要聘請專家來了解應用程序的目的), 它必須是唯一負責業務規則的人 因此,對於簡單的驗證,您不需要任何驗證框架。

您需要的是表達性異常 ,可以輕松映射到正確定義的故障。

編輯以回答新問題

在WCF中,我經常在DTO構造函數中使用輸入驗證,因此客戶端無法發送“無效請求”。 這具有許多優點,例如,客戶端不能使用無效輸入來配置DOS攻擊。 此外,如果你有大量的客戶端,這可以減少網絡負載,並使用戶體驗更好一點,因為他不需要等待服務器響應只是為了知道他忘記了電子郵件字段中的@。

但實際上,年齡超過18歲是一個商業規則,而不是輸入規則。

輸入規則可以是:“Age字段必須大於Zero”,因為負年齡是不可能的,零年齡聲音太像用戶錯誤(並且它是int32默認值)。

但合同驗證還不夠

如果年齡在您的域中相關,您將擁有Age結構,包裝UInt32 (因此之前是輸入規則)。 為什么要包裝UInt32 例如,因為在您的域模型中,您知道兩個用戶年齡的總和沒有意義。

是的,你最多檢查一次該號碼(一個在客戶端,兩個在服務器上),但這是正確的,這里。 DTO可以獨立於域模型發展,域模型不會冒出意外行為的風險(或者根本不需要域模型)。

要了解業務規則,請考慮跟蹤某種特殊治療方法的醫療記錄應用程序: 命令 void Prescribe(Age patientAge, AntibioticPrescription prescription)可以檢查患者的年齡參數是否大於之前處方的年齡。 這是一個商業規則。 另一項業務規則應檢查當前處方與前一處方之間的危險交互。

如果是這樣,該命令應記錄並拋出 3個異常:

  • ArgumentNullException ,當處方為null時(假設它是引用類型)
  • InconsistentAge ,當患者年齡低於最后一位時
  • MortalPrescription ,當這樣的處方可以殺死病人。

這些異常表達了業務規則的前提條件 (除了參數null,當程序員引入某種錯誤時,它會盡快失敗)。

從任何UI或外部處理隱藏我們的域對象總是一件好事。 這也允許您創建稍微不同的對象結構,因為您的域模型可能對數據庫圖表非常緊密,並且不能始終反映對象的邏輯含義。

意思是,不,您不應該通過服務直接公開實體。

要將實體轉換為DTO,我在大多數情況下都使用Automapper,這非常方便。

關於驗證,您可以在實體上使用數據注釋來驗證它們。

但是,如果您的DTO反映了不可能單獨使用注釋驗證的不同類型或更復雜的業務邏輯,則可以使用類似流暢驗證的內容 ,這非常靈活且易於設置。

我目前正在一個項目中使用它們。 例如,對於標准驗證,如必填字段,字段長度甚至電子郵件或電話號碼驗證,您可以使用帶有正則表達式的簡單數據注釋等。

對於復雜的事情,如果字段A是空的字段B不能為空等...,您可以使用流暢的驗證......這實際上取決於您是在實體或DTO級別上執行此操作。 如果您沒有任何僅由DTO反映的自定義邏輯(可以是視圖模型)(就MVC而言),您可以在實體級別上執行所有這些操作。

這也取決於您的應用程序是否是使用實體的唯一應用程序。 如果您計划將您的實體和數據訪問層公開為api給其他開發人員,那么大多數驗證應該在該級別上完成。

我應該創建DTO嗎? 將實體直接暴露給wcf客戶端是否有任何危害?

  1. 你應該創建DTO。 當實體通過DataContract公開時,WCF會從客戶端可能發送到服務器的任何垃圾中創建這些實體。 即使您計划稍后驗證狀態,創建具有無效/不一致狀態的實體也是不好的做法。

如果我暴露DTO,我應該驗證DTO以及實體。 如果我只驗證DTO,那么我沒有為我的Enitity對象提供任何輸入驗證。 這個可以嗎?

  1. 無論您是否驗證實體,都應驗證DTO。 如前所述,DTO包含來自客戶端的任何垃圾。 服務層負責驗證每個服務方法參數值,並使用正確的值調用基礎域層。

  2. 如果您確定在訪問實體之前進行所有數據驗證,則可以從實體中刪除驗證。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM