recently i’ve decided to use viewmodels instead of EF EntityObjects.
i’m sure that there will be no problems for GET requests but i want to know what to do with create and update actions.
i’ve read a lot of discussions and decided that i’ll act int this way.
but another questions appeared:
1) when i was using EF EntityObjects with annotations the validation logic was stored in one place, but if i have different viewmodels in different projects, then i’ll have to duplicate validation rules. isn’t it violation of the DRY principle?
2) i’ve read several posts about viewmodels and validation where people suggest to validate input in viewmodels and business rules in domain models but i can’t realize how can i call validation that is defined in domain models if my actions have viewmodels as parameters:
public class MyDomainModel : IValidatableObject
{
public string Title;
// validation of business rules
}
public class MyViewModel
{
[Required]
public string Title;
}
public ActionResult Edit(MyViewModel item)
{
if (ModelState.IsValid) // MyViewModel's rules are validated not MyDomainModel's
{
...
}
If you switch to ViewModels you should let the framework perform validation via DataAttributes in your ViewModel classes. That is just a formal check on input, then you should validate according to your business rules (sometimes with just data annotations is just impossible to cover al the scenarios), and in case of errors, add them to the modelstate.
Example:
in your Post Action you can do something like:
Obviously I’m keeping it very simple.
Following this pattern sure add a little overhead in term of code, but checks have to be done both client side (just a formal validation on input) and server side (both formal and semantic validation). I prefer to have all semantics in a business assembly, leaving formal checks to the MVC unobtrusive validation engine (just some UI sugar in my views, yes, I hate Javascript) .
Usually my Business Objects use ViewModel’s properties considering them readonly (just the usefull ones to prevent bad injections) and do the dirty/heavy job.
This may not be the perfect solution for everything, but I’ve noticed that applying this pattern (and force other member of the team to do the same), is leading to a good codebase.
Yes, we’re still far from perfection, I’d like to write both semantics and formal checks just once, but that’s how web is working right now.
Let me know if you need further advice or if I’ve completely misunderstood your question.
PS: once you choose a pattern, stick to it no matter what.
EDIT: (long comments are a no no)
In the constructor I usually apply mappings on fields I need to change, I try to consider the ViewModel properties as readonly, to avoid unwanted modifications.
My
IsValid()method just holds business checks (for example, given an ID it checks for real existence in a certain table or given a username checks if he can actually access certain data).It’s just a separation between ViewModel validation (for me is just syntactic => strings are strings, integer are integer, positive numbers are >= 0, string lengths are respected, ranges are met and so on) and real business validity (semantic => a user can access some data, an object is valid in the scope of the application).
Of course the Business validation layer can also be simple (or not exists at all), I prefer to keep them separated for reusability (often my business logic is shared between an
MVCapplication and aWPFapplication). It’s a bit of extra work but on the long run it pays better, I can use my complex business logic everywhere. (and working with Banks, it’s the greatest goal. Change logic in just one assembly, for instance to add a new check on something, and being confident that each application using that assembly will be up to date).So definitely is a more of extrawork, but I think it’s better investing a few dev hours before than wasting days lately for maintenance/evolutions.
Nowadays programming seems reduced to a go-and-forget activity, (due to reduce time/budget or simply because we do our task and then change employee), but each line that is coded, will need some kind of maintenance in the future, so it’s better to keep things ordered and clean, preferring maintenance ease against developing speed.