We put all of our DataAnnotations on our Model class Customer. We then expose an instance of Customer as a property on our associated ViewModel along with some lookup lists for Countries etc and display this in our View. All's good so far.
We then read on SO and other sources that we shouldn't be passing our entire Customer model object to the View for the reasons of only providing the View with the bare minimum it needs and more importantly (for us) to prevent possible issues when ModelBinding potentially malicious postbacks that add additional information to change our models properties that otherwise were not available in the view.
How do we get all of those DataAnnotation attributes off the model object and onto the possibly cut down ViewModel properties without throwing the DRY principle over the cliff?
Also, are we correct in thinking that we shouldn't be using TryUpdateModel against an entity that we pull from the开发者_如何转开发 db? I guess our choice is to either use TryUpdateModel and pass an exclusion list of properties which doesn't seem particularly elegant to me given that the list is just a param of type string. Or perhaps we should do away with TryUpdateModel and use a tool such as AutoMapper which is more type safe?
Thanks for any thoughts on these issues.
How do we get all of those DataAnnotation attributes off the model object and onto the possibly cut down ViewModel properties without throwing the DRY principle over the cliff?
You can't. It's the price to pay, but I think it's pretty cheap because in fact in this stripped down version the validation attributes might be different and you might have different validation properties according to the requirements of the view. Let's take an example: New
and Edit
view. In the Edit
view, the Id
of the entity will be required, while in the New
view not required as it will be assigned by the data store (in fact in your new model there might not even be an Id property).
Also, in general I place the validation attributes only on the view model but this might not be the best approach as if you wanted to reuse your models in different applications, there won't be any validation logic on them.
Also, are we correct in thinking that we shouldn't be using TryUpdateModel against an entity that we pull from the db?
Personally I never use TryUpdateModel
. I prefer passing a view model as a controller action parameter and leave the default model binder do the job. In this case of course you don't need any inclusion or exclusion properties list because this view model is exactly tailored to the given view.
As far as AutoMapper is concerned it's a must have tool for converting between your model classes (which appear in your repository method signatures) and the view models which are passed to and from the view.
I have found that placing validation attributes ONLY on the ViewModel and keeping the model object alone was the best approach.
The view models are validated when a user posts any data and if the data is valid, the business layer takes care of creating the object model in the database with the data the user sent in.
In the services/business layer classes, functions that update or add only accept the necessary values for a object model (strings, ints, etc.) but never an entire object. The service class is responsible for creating the object.
By placing the validation on the view model, you ensure that any and all data passed into your business logic layer is valid and you can safely commit changes.
精彩评论