问题
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.
I am exposing DTO to my clients. I have below questions
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) 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) 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
Having DTO at times seem redundant to me but i can use it to club details from one or more entities.
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)
Edit
Based on the response I kind of now agree to retain the DTO layer, Here is an exmaple so that scenario become more explicit
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.
Should Input Validation be only applied at service interface layer as we get DTO from client or it should also be applied on CustomerEntity
回答1:
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?
Yes, SOA requires data contracts.
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.
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?
You should validate the "contract", not the business rules.
For example a WCF DTO can require some fields to be populated, and I would use ArgumentNullException
in the constructors.
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.
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
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.
edit to answer the new questions
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.
But actually being older than 18 is a business rule, not an input rule.
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).
However contract validation is not enough.
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.
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).
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.
If so, this command should document and throw 3 exceptions:
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.
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).
回答2:
having DTOs is always a good thing to hide our domain objects from any UI or external processing. This also allows you to craft a slightly different object structure because your domain model might be pretty much tight to your database diagram and must not always reflect the logical meaning of the objects.
Meaning, no, you shouldn't expose the entities directly via services.
To transform Entities to DTOs I'm using Automapper in most scenarios, which is pretty handy.
Regarding validation, you can use data annotations on your entities to validate them for example.
But if your DTOs reflect different kind of or more complex business logic which is not possible to validate with annotations alone, you could use something like fluent validation, which is very flexible and easy to setup.
I'm currently using those in one project. For example, for standard validations like required fields, field length or even email or telephone number validation you can use simple data annotations with regular expressions etc.
For complicated things like if field A is empty field B must not be empty etc..., you can use fluent validation... And it really depends if you do that on the entity or DTO level. If you do not have any custom logic only reflected by the DTO which could be a View Model (in terms of MVC) you can do all this on the entity level.
It also depends if your application is the only application using the Entities. If you plan to expose your entity and data access layer as api to other developers, most of the validation should be done on that level.
回答3:
Should i create DTOs? is there any harm in exposing entities directly to wcf clients
- You should create DTOs. When entities are exposed though DataContract, WCF creates these entities from any garbage that client can possibly send to the server. It is bad practice to create entities with invalid / inconsistent state even if you plan validating the state later.
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?
You should validate DTOs regardless of whether you validate entities or not. As already said, DTOs contain any garbage from client. It's responsibility of Service Layer to validate every service method parameter value, and call the underlying Domain Layer with only correct values.
It is OK to remove validation from entities if you are sure to do all data validations before accessing entities.
来源:https://stackoverflow.com/questions/20091826/should-dto-and-entity-both-have-input-validations