Reputation: 26028
If client validation
is done when is it necessary to do domain level validation
?
I use ASP.NET MVC
for my web applications. I like to distinguish between my domain models
and view models
. My domain models contain the data that comes from my database and my view models contain the data on my views/pages.
Lets say I am working with customer data.
I will have a table in my database called Customers
.
I will have a customer class which could look something like this:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
And I will a create customer view model to represent only the data that I have on my view:
[Validator(typeof(CustomerCreateViewModelValidator))]
public class CustomerCreateViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
I will have a create view that accepts my CustomerCreateViewModel
and binds my input fields to my view model:
@model MyProject.ViewModels.Customers.CustomerCreateViewModel
@using (Html.BeginForm())
{
<table>
<tr>
<td>
@Html.TextBoxFor(x => x.FirstName)
@Html.ValidationMessageFor(x => x.FirstName)
</td>
</tr>
<tr>
<td>
@Html.TextBoxFor(x => x.LastName)
@Html.ValidationMessageFor(x => x.LastName)
</td>
</tr>
</table>
<button id="SaveButton" type="submit">Save</button>
}
As you can see I have a CustomerCreateViewModelValidator
that contains my validation rules. After the user has entered some data into the text boxes he will click the submit button. If some of the fields are empty then validation fails. If all the required fields are entered then validation succeeds. I will then map the data from my view model to my domain model like this:
Customer customer = Mapper.Map<Customer>(viewModel);
This customer domain model I take and pass it onto my repository layer and it adds the data to my table.
When does validation need to be done on a domain model? I do all my validation on my view model. I can validate my data in my domain model just before I add it to the database but seeing that it was validated on the view model wouldn't it be just replicating the same validation on the client side?
Could someone please share some light on this validation matter?
Upvotes: 23
Views: 5607
Reputation: 19987
As a general rule I consider the domain model to be the most important code and therefore management of its state holy. For that reason I would never assume for the domain model to be in a valid state just because it was operated on by a presentation layer that is supposed to enforce validity. This would mean your domain layer is tightly coupled to your presentation layer.
It is best to start thinking from the domain model outwards (onion architecture). The reasoning behind all this is that the domain model is the least likely to change over time and acts as a core to an application, insulating layers from each others' flaws.
So starting with a domain model that enforces its own validity you are left with the question of duplication of validation code. There are some ways to avoid this. Your view model may for example try to create a domain object and translate any exceptions thrown as validation failures. Validators can also be extracted and reused. Depending on your use-cases you have to see what works best for you. Just beware to keep it simple. Perhaps, if your use-cases are not to though, it might be most maintainable to simply duplicate the validation. Remember that deduplication increases complexity.
I have seen code bases in which only the domain layer handled the validation and codebases in which validation was handled in both the domain- and the presentation layer. I have a preference to simply duplicating the validation logic at this point, because I have seen how hard it is to meaningfully map domain validation errors well to a contextual user-interface.
Upvotes: 8
Reputation: 1318
Always validate at both levels.
You need to validate the view models because you want to feed back to the user as quickly and easily as possible if they've done something wrong. You also don't want to be bothering the rest of your domain logic if the model is invalid.
But, you will also want to verify that everything's happy in the domain, once the view model has been validated. For simple models, these checks may be the same, and so it does look like duplicating logic, however as soon as your application grows so you may have multiple user interfaces, or many different applications using the same domain models, it becomes so important to check within the domain.
For example, if your application grows so you end up providing an API to customers to interact directly with the application programmatically, it becomes a necessity to validate the domain models, since you cannot guarantee that the user interface used has validated the data to the standard that you need (or even validated it at all). There is an argument to say that the data received by APIs should be validated in much the same way as the view models are validated, and that's probably a good idea since that is achieving the same goal as the view model validation is. But regardless of the route in (either from a UI or the API), you will want to always guarantee that the data is valid, so defining that in a central place is ideal.
The aims of the two levels of validation is different, too. I would expect a view model validation to inform me of all problems (such as missing first name, last name is too long, DoB is not a date). However, I think it would be ok for the domain logic to fail on the first error, and just report that one. Again, for simple models, it may be possible to collect all errors and report them all back, however the more complex an application gets, the harder it gets to anticipate all errors, especially if the logic will change depending on the data. But, as long as only good data gets past, that should be fine!
Upvotes: 18
Reputation: 29186
I tend to think of client validation as more sanitizing the data at the UI level. In other words, checking that, for example, an input field that is a number is given a number by the user. Or whether the length of a text input meets the minimum length requirement. Stuff like that.
At the domain level, you should be checking business domain rules. For example, if the user is entering details about a new Product, does the product name already exist? Or maybe checking that the user has a selected a valid Department when configuring a new User, based on that User's skills? This are just out of the air examples, but I hope they give an idea of what I mean.
Upvotes: 2
Reputation: 2577
You would need to have a model validator in case you have several clients for your model. For instance if you have ASP.NET MVC calling your model and a WPF application, in this case it makes sense to have the validation logic on the model. But in your case where you got only one client that would be overkill.
Upvotes: 0