问题
Suppose you have an application that utilizes the domain-model pattern, DDD and lots of other design patterns. assume that we have a number of solutions as listed below:
- Solution.Model
- Solution.Repository
- Solution.Services
- Solution.Presentation
- Solution.UI.Web
The user experience layer will be Solution.UI.Web and we'll assume that it'll be an ASP.NET WebForms application. how do you enforce client-side validation?
There are a number of things to be considered:
First and foremost, we shouldn't have to hit the application/database server(s) to return any validation errors to the client, we could however implement server-side validation too, but we're gonna need client-side validation as well.
Second, we don't want to implement the validation rules on the user experience layer. that's because if your application is a WebApp and then you decide to create a WinApp client as well, you're gonna have to implement the validation rules all over again --> maintenance nightmare.
One simple approach would be to implement your validation logic withing your ViewModel objects (flattened views of your domain entities that will be sent to the client) and then validate those objects before hitting the application/database server(s).
Another approach, one that I have seen used many times in different applications, is to just generate a collection of validation error messages and send that collection to the client. that's fine, but there's a problem. just a simple summary message of validation errors won't do, specially if you have big data entry form.
Now the ASP.NET MVC framework makes life much easier. you can use EF + DataAnnotations, and MVC Scaffolding framework can do most of the job for you. but that's the case if you want to create an MVC application and implement your validation logic with jQuery and JavaScript.
But what if you need a more generic approach to implement a validation framework that can be utilized and used in different applications, say WinForms and WebForms ?
Just to clarify, what im looking for is a set of design patterns/principles and/or techniques/frameworks to implement a validation framework that can be implemented withing your domain model and then be enforced on your client applications. And, I don't want to just return a collection of string error messages about the broken rules or anything, I want to be able to update my data-bound controls (TextBox, ComboBox, DateTimePicker, etc) upon validation failure so that the user experience layer would be more intuitive (if you will).
I have seen some implementations and frameworks here and there, and I have used ASP.NET MVC client-side validation for a while now, so my answer doesn't have anything to do with MVC or JavaScript validation.
回答1:
I have not come across an all encompassing validation solution. One reason for this is that validation logic can be subtly different depending on the application layer. For example, not all rules enforced by the domain layer can be enforced on the client side and so there will always be cases where client side validation may pass and yet you still need to display a validation message which propagated from the domain layer.
However, the validation model in ASP.NET MVC is extensible and you can extend it to support additional validation rules or event a validation framework other than DataAnnotations. Here is an example of integrating Enterprise Library Validation block with ASP.NET MVC, however as the article points out, client side validation was not implemented. Another approach would be to use DataAnnotations attributes in your domain layer. The DataAnnotations namespace is not tied to ASP.NET MVC.
The challenge in these approaches however is that of propagating validation rules from domain objects to view models. In theory, you can extend AutoMapper such that validation rules from a domain model are carried over to view model classes, however the cost of implementation and maintenance may outweigh the benefits of this solution.
The Fluent Validation framework could be used as a starting point for an all encompassing validation solution. There are many examples of using this framework with ASP.NET MVC.
回答2:
In DDD, domain is usually self validating. In other words objects are not allowed to be in invalid state. Value objects help a lot here. They simply encapsulate formatting rules. For example you can have class ZipCode that is guaranteed to always be well formed. As an additional responsibility it can have a static method like ZipCode.TryParse or ZipCode.Validate that will take arbitrary string as parameter and validate. This way validation logic is concentrated in one place. If your domain objects are accessible directly from UI than you don't need to duplicate this logic anywhere else. This is the case for fat clients (Windows Forms, WPF). Unfortunately there is no way to avoid some duplication for web clients when they are required to perform validation without round-tripping to server.
回答3:
You should encapsulate the validation logic in simple classes which represent your domain knowledge.
I write about it in my primitive obsession blog post. Here's how your ASP.NET MVC controller may look like if you create such classes:
public class CustomerController : Controller
{
[HttpPost]
public ActionResult CreateCustomer(CustomerInfo customerInfo)
{
Result<Email> emailResult = Email.Create(customerInfo.Email);
Result<CustomerName> nameResult = CustomerName.Create(customerInfo.Name);
if (emailResult.Failure)
ModelState.AddModelError("Email", emailResult.Error);
if (nameResult.Failure)
ModelState.AddModelError("Name", nameResult.Error);
if (!ModelState.IsValid)
return View(customerInfo);
Customer customer = new Customer(nameResult.Value, emailResult.Value);
// Rest of the method
}
}
No need to use Annotations because they essentially encourage you to duplicate the validation logic.
Compare these code samples:
- With primitive obsession
- Without primitive obsession
来源:https://stackoverflow.com/questions/6966288/ddd-client-side-validation