1)我应该创建DTO吗?直接向 WCF 客户端公开实体是否有任何危害,因为我的实体也将具有业务逻辑方法,这样做我将不得不使用我认为不好的 WCF 属性来破坏我的实体对象?
是的,SOA 需要data合同。
它们或多或少可以是正式的(CSV、JSON、XSD、WSDL、WADL,甚至 HTML 或 txt 文件),但如果您无法找到此类合同的协议,则不应采用任何“服务”技术或技巧(也没有任何其他 IPC)。
远程处理是唯一试图避免这种要求的技术。从抽象的角度来说,这是一个了不起的想法,但具体来说却行不通。
2)如果我公开DTO,我是否应该验证DTO以及实体。如果我仅验证 DTO,那么我不会为我的实体对象提供任何输入验证。这个可以吗?
您应该验证“合同”,而不是业务规则。
例如,WCF DTO 可能需要填充一些字段,我会使用ArgumentNullException
在构造函数中。
但您应该记住,DTO 的作用是传输数据。如果您有一个数字字段,由于某种奇怪的原因必须作为字符串传输,您可以验证它,例如防止 DTO 初始化。
3)我是否应该考虑使用架构验证来验证应用程序服务层(WCF 层)中的 DTO?或者我应该使用文章[博客]中给出的 IValidator 方法:http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/ http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/正如吉米·博加德所示
如果您需要域模型(这意味着您需要聘请专家了解应用目的),它必须是唯一对业务规则负责的。因此,对于简单的验证,您不需要任何验证框架。
你需要的是表达性例外 http://epic.tesio.it/2013/03/04/exceptions-are-terms-ot-the-ubiquitous-language.html可以轻松地将其映射到正确定义的故障。
编辑以回答新问题
在WCF中,我经常在DTO构造函数中使用输入验证,以便客户端不能发送“无效请求”。这有很多优点,例如客户端不能使用无效输入来配置 DOS 攻击。此外,如果您有大量客户端,这可以减少网络负载,并使用户体验更好一些,因为他不需要等待服务器响应就知道他忘记了电子邮件字段中的@。
但实际上年龄超过 18 岁是一个业务规则,而不是一个输入规则。
输入规则可以是:“年龄字段必须大于零”,因为负年龄是不可能的,并且零年龄听起来太像用户错误(并且它是 int32 默认值)。
然而合同验证并不enough.
如果年龄与您的领域相关,您将有一个Age
结构体,包装一个UInt32
(就这样input之前的规则)。为什么要包裹一个UInt32
?例如,因为在您的领域模型中,您知道两个用户年龄的总和没有意义。
是的,您最多检查该数字 3 次(一次在客户端,两次在服务器),但这是正确的做法,在这里。 DTO 可以独立于领域模型而发展,并且领域模型不能冒险意外行为(或者您根本不需要域模型)。
要了解业务规则,请考虑一个跟踪某种专门治疗类型的医疗记录应用程序:command http://epic.tesio.it/doc/manual/command_query_separation.html void Prescribe(Age patientAge, AntibioticPrescription prescription)
可以检查患者年龄参数是否大于先前处方的年龄。那是一个business规则。另一项业务规则应该检查当前处方与前一个处方之间是否存在危险的相互作用。
如果是这样,这个命令应该记录并抛出3 个例外:
-
ArgumentNullException
,当处方为空时(假设它是参考类型)
-
InconsistentAge
,当提供的患者年龄低于上一个时
-
MortalPrescription
,当这样的处方可能会杀死病人时。
此类异常表示前提条件 http://www.stanford.edu/class/cs295/lectures/lecture03.pdf那是business规则(除了参数 null,当程序员引入某种错误时,它会尽快失败)。