问题描述
我有一个WCF层,并且我的域模型在此WCF层后面。我将Nhibernate用作ORM工具,我所有的业务逻辑/数据访问等都将在WCF层后面。
I have a WCF layer and my Domain Model is behind this WCF layer. I am using Nhibernate as an ORM tool and all my business logic/ Data Access etc will be behind this WCF layer.
我将DTO暴露给我的客户。我有以下问题
I am exposing DTO to my clients. I have below questions
1)我应该创建DTO吗?将实体直接暴露给wcf客户端是否有任何危害,因为我的实体在这样做时也会有业务逻辑方法,因此我不得不使用我认为不好的WCF属性破坏实体对象?
1) Should i create DTOs? is there any harm in exposing entities directly to wcf clients as my entities would also have business logic methods also in doing so i would have to corrupt my entitiy object with WCF attributes which i think is not good?
2)如果我公开了DTO,我是否应该同时验证DTO和实体。如果我仅验证DTO,则不会为我的Enitity对象提供任何输入验证。可以吗?
2) If i expose DTO, should i be validating DTO as well as Entity. If i validate only DTO then i am not providing any input validations for my Enitity object . is this ok?
3)我是否应该考虑使用模式验证在Application Service层(WCF层)中验证DTO?还是我应该使用文章[blog]中提供的IValidator方法:由吉米·鲍嘉(Jimmy Bogard)显示
3) Should i consider validating the DTO in the Application Service layer (WCF layer) using Schema validation? or Should i use IValidator Approach given in article [blog]: http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/ as shown by Jimmy Bogard
对我而言,有时具有DTO似乎是多余的,但我可以使用它来合并一个或多个实体的详细信息。
Having DTO at times seem redundant to me but i can use it to club details from one or more entities.
我会公开这项服务提供给各种客户,因此我的DTO将从具有凭证详细信息的基本dto派生,我会在实际wcf方法调用之前检查每个传入请求(可能使用IEndpointBehaviour和IParamInspector)
I would be exposing this service to various client and thus my DTO will be deriving from some base dto having credential details which i would check for each incoming request before my actual wcf method call (probably using IEndpointBehaviour and IParamInspector)
基于响应,我现在同意保留DTO层,这是例如,使场景变得更加清晰
Based on the response I kind of now agree to retain the DTO layer, Here is an exmaple so that scenario become more explicit
说我在WCF应用程序中有CreateCustomer方法接受CustomerDetailsDTO在服务层(可能由MVC应用程序调用)上。有一些输入验证,例如
输入验证:
Say I have CreateCustomer method accepting CustomerDetailsDTO in my WCF Application Service Layer which may be called by an MVC application.There are some input validations like
Input Validations:
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
业务验证:
Business Validations:
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
Should Input Validation be only applied at service interface layer as we get DTO from client or it should also be applied on CustomerEntity
推荐答案
是的,SOA需要数据合同。
Yes, SOA requires data contracts.
它们可以或多或少正式的格式(CSV,JSON,XSD,WSDL,WADL甚至HTML或txt文件),但是如果找不到此类合同的协议,则不应采用任何服务技术或技术(也不应采用任何其他IPC来实现)
They can be more or less formalized (CSV, JSON, XSD, WSDL, WADL even HTML or a txt file) but if you can't find an agreement on such contracts, you shouldn't adopt any "service" technology or technique (nor any other IPC for what it matter).
远程处理是唯一尝试避免这种要求的技术。从抽象上来说,这是一个了不起的主意,但具体来说却行不通。
Remoting was the only technology that tried to avoid such requirement. It was an amazing idea, in abstract, but concretely it didn't work.
您应该验证合同,而不是业务规则。
You should validate the "contract", not the business rules.
例如,WCF DTO可能需要填充某些字段,而我将在构造函数中使用 ArgumentNullException
。
For example a WCF DTO can require some fields to be populated, and I would use ArgumentNullException
in the constructors.
但是您应该记住DTO用于传输数据。如果您有一个数字字段,由于某种奇怪的原因而必须将其作为字符串进行传输,则可以对其进行验证,例如,防止DTO初始化。
But you should remember that DTOs serve to transfer data. If you have a numeric field that for some strange reason have to be transferred as a string, you can validate it, for example preventing the inizialization of the DTO.
如果您需要域模型(这意味着您需要雇用专家以了解应用目的),它必须是唯一负责业务规则的人。因此,对于简单的验证,您不需要任何验证框架。
If you need a domain model (that means that you need to hire an expert to understand the application purpose), it has to be the only responsible for business rules. Thus for simple validations, you shouldn't need any validation framework.
您需要的是,可以轻松将其映射到正确定义的故障。
What you need are expressive exceptions that can be mapped easily to properly defined faults.
编辑以回答新问题
在WCF中,我经常在DTO构造函数中使用输入验证,以便客户端无法发送无效请求。这样做有很多优点,例如,客户端不能使用无效输入来配置DOS攻击。此外,如果您有大量客户端,这可以减少网络负载,并使用户体验更好,因为他不必等待服务器响应即可知道他在电子邮件字段中忘记了@。
In WCF, I often use input validation in the DTO constructors, so that the client can not send "invalid requests". This has many advantages, for example the client can't use invalid input to configure a DOS attack, for example. Moreover if you have a large number of clients this can reduce the network load, and make the user experience a bit better since he doesn't need to wait for a server response just to know that he forgot a the @ in an email field.
但实际上,年龄大于18岁是业务规则,而不是输入规则。
But actually being older than 18 is a business rule, not an input rule.
输入规则可以是:年龄字段必须大于零,因为不可能使用负年龄,并且零年龄听起来太像用户错误(这是int32的默认值)。
An input rule could be: "the Age field must be greater than Zero", because negative age are not possible, and a zero age sound too much like an user error (and it is the int32 default value).
但是合同确认没有足够。
如果年龄与您的域相关,则您将获得 Age
结构,包装 UInt32
(因此之前是 input 规则)。为什么要包装 UInt32
?例如,因为在您的域模型中,您知道两个用户的年龄之和没有意义。
If the age is relevant in your domain you will have a Age
struct, wrapping an UInt32
(thus the input rule before). Why wrap an UInt32
? For example because in your domain model you know that the sum of two users's age has no meaning.
是的,您最多检查了3次该数字(在客户端一次)和两个在服务器上),但这是正确的选择。 DTO可以独立于域模型而发展,并且域模型不能冒意外行为的风险(或者根本不需要域模型)。
Yes, you check that number at most 3 times (one on the client and two on the server), but that's the right thing to do, here. The DTOs could evolve indipendently of the domain model, and a domain model cannot risk unexpected behaviour (or you don't need a domain model at all).
要了解业务规则,请考虑记录某些特殊疗法的病历应用程序: void Prescribe(年龄PatientAge,AntibioticPrescription处方)
可以同时检查两个PatientAge参数是否大于以前的处方年龄。这是业务规则。另一条业务规则应检查当前处方与先前处方之间是否存在危险的相互作用。
To get an idea of a business rule, think of a medical record application that keep track of some specialized kind of therapy: the command void Prescribe(Age patientAge, AntibioticPrescription prescription)
could check both the patientAge argument to be greater than the previous prescription's age. That's a business rule. Another business rule should check for dangerous interactions between the current prescription and the previous one.
如果是,此命令应记录并抛出 3个异常:
If so, this command should document and throw 3 exceptions:
-
ArgumentNullException
,当处方为空时(假设它是引用类型) -
InconsistentAge
,如果提供的PatientAge低于最后一个 -
MortalPrescription
,这种处方可能会杀死病人。
ArgumentNullException
, when the prescription is null (assuming it's a reference type)InconsistentAge
, when the patientAge provided is lower than the last oneMortalPrescription
, when such prescription could kill the patient.
此类例外表示是 business 规则(参数null除外,当程序员引入某种错误时,它会尽可能快地失败)。
Such exceptions express preconditions that are business rules (except the argument null, that is there to fail as fast as possible when programmers introduce some kind of bugs).
这篇关于DTO和Entity都应具有输入验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!