我有一个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层,这是一个例子,以便场景变得更加明确
假设我在我的WCF应用服务层中接受CustomerDetailsDTO的CreateCustomer方法可以由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
答案 0 :(得分:6)
1)我应该创建DTO吗?将实体直接暴露给wcf客户端有什么害处,因为我的实体也会有业务逻辑方法这样做我不得不用WCF属性来破坏我的权利对象,我觉得这样做不好?
是的,SOA需要数据合同。
它们可以或多或少地形式化(CSV,JSON,XSD,WSDL,WADL甚至HTML或txt文件),但如果您无法就此类合同找到协议,则不应采用任何“服务”技术或技术(或任何其他IPC的重要性)。
Remoting是唯一试图避免此类要求的技术。这是一个惊人的想法,抽象,但具体来说它没有用。
2)如果我公开DTO,我应该验证DTO以及实体。如果我只验证DTO,那么我没有为我的Enitity对象提供任何输入验证。这样可以吗?
您应该验证“合同”,而不是业务规则。
例如,WCF DTO可能需要填充一些字段,我会在构造函数中使用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所示
如果您需要域名模型(这意味着您需要聘请专家来了解应用目的),必须是唯一负责业务规则的 。因此,对于简单的验证,您不需要任何验证框架。
您需要的是expressive exceptions,可以轻松映射到正确定义的故障。
编辑以回答新问题
在WCF中,我经常在DTO构造函数中使用输入验证,因此客户端无法发送“无效请求”。这具有许多优点,例如,客户端不能使用无效输入来配置DOS攻击。此外,如果您拥有大量客户端,这可以减少网络负载,并使用户体验更好一点,因为他不需要等待服务器响应就知道他忘记了电子邮件字段中的@。
但实际上,年龄超过18岁是商业规则,而不是输入规则。
输入规则可能是:“Age字段必须大于Zero”,因为负年龄不可能,零年龄声音太像用户错误(并且它是int32默认值)。
然而,合同验证不够 。
如果年龄与您的域名相关,则您将拥有一个Age
结构,其中包含UInt32
(因此之前的输入规则)。为什么要包裹UInt32
?例如,因为在您的域模型中,您知道两个用户年龄的总和没有意义。
是的,你最多检查一次该号码(一个在客户端,两个在服务器上),但这是正确的,这里。 DTO可以独立于域模型发展,域模型不会冒意外行为(或者您根本不需要域模型)。
要了解业务规则,请考虑一个跟踪某种特殊治疗方法的医疗记录应用程序:command void Prescribe(Age patientAge, AntibioticPrescription prescription)
可以检查PatientAge参数是否大于以前处方的年龄。这是商家规则。另一项商业规则应检查当前处方与前一处方之间的危险互动。
如果是这样,该命令应记录并抛出 3例外:
ArgumentNullException
,当处方为空时(假设它是参考类型)InconsistentAge
,当提供的患者年龄低于最后一个时MortalPrescription
,当这样的处方可以杀死病人时。此类异常表示preconditions是业务规则(除了参数null,当程序员引入某种错误时,会尽快失败)。
答案 1 :(得分:3)
让DTO隐藏任何UI或外部处理中的域对象总是一件好事。这也允许您创建一个稍微不同的对象结构,因为您的域模型可能对数据库图表非常紧张,并且不能总是反映对象的逻辑含义。
意思是,不,你不应该直接通过服务公开实体。
将实体转换为DTO我在大多数情况下都使用Automapper,这非常方便。
关于验证,您可以在实体上使用数据注释来验证它们。例如。
但是,如果您的DTO反映了不可能单独使用注释验证的不同类型或更复杂的业务逻辑,那么您可以使用类似fluent validation的内容,它非常灵活且易于设置。
我目前正在一个项目中使用它们。 例如,对于标准验证,如必填字段,字段长度甚至电子邮件或电话号码验证,您可以使用带有正则表达式等的简单数据注释。
对于复杂的事情,如果字段A为空,字段B不能为空等...,您可以使用流畅的验证......这实际上取决于您是在实体还是DTO级别上执行此操作。如果您没有任何仅由DTO反映的自定义逻辑(可以是视图模型(就MVC而言),您可以在实体级别执行所有这些操作。
这还取决于您的应用程序是否是使用实体的唯一应用程序。如果您打算将您的实体和数据访问层公开为api给其他开发人员,那么大多数验证都应该在该级别上完成。
答案 2 :(得分:0)
我应该创建DTO吗?将实体直接暴露给wcf客户端是否有任何伤害
如果我公开DTO,我应该验证DTO以及实体。如果我只验证DTO,那么我没有为我的Enitity对象提供任何输入验证。这样可以吗?
无论您是否验证实体,都应验证DTO。如前所述,DTO包含来自客户端的任何垃圾。服务层负责验证每个服务方法参数值,并使用正确的值调用基础域层。
如果您确定在访问实体之前进行所有数据验证,则可以从实体中删除验证。