views:

282

answers:

3

I'm struggling to mesh two best practices together:

  1. Using DataAnnotations + ModelBinding for validation in ASP.NET MVC 2
  2. Using DTOs instead of domain entities when passing data via the ViewModel

If I want to pass over DTOs instead of domain entities, then leveraging DataAnnotations + ModelBinding for validation would require me to specify validation attributes on my DTO classes. This results in a lot of duplicated work since multiple DTOs may hold overlapping fields with the same validation restrictions. This means that any time I change a validation rule in my domain, I have to go find all DTOs that correspond with that value and update their validation attributes.

+3  A: 

You shouldn't have more than one DTO per entity, so you should only have to apply the validation attributes once per DTO. If you need multiple entities for a View, include multiple DTO's as properties of your ViewModel.

Dave Swersky
That seems a bit restrictive. What if one view needs all the properties of an entity while another view only needs a few? Wouldn't that use case call for multiple DTOs?
Kevin Pang
I agree with Kevin, I could think of instances were I would want multiple DTOs for display purposes. However, only having one DTO for submitting data would be a sensible approach.
roryf
Dave Swersky
Right, I understand the need to mix and match DTOs. Where this breaks down, I think, is when your DTOs contain too much information. For example, if you needed to support two views for displaying a single product entity's information, one for admins and one for normal users. The admin view might require a complex DTO that flattens the product and its relationships while the normal user view might only require a basic DTO with far less information. How would you handle that?
Kevin Pang
DTO's are storage-independent "flattened" versions of your Model(s). There should be only one DTO per Entity. I would not create a DTO that includes both a product and its related Entities. It is the role of the ViewModel to aggregate related data together to support the needs of a View.
Dave Swersky
Fair enough, but what if the admin view needed, say, 100 attributes of a product while a normal view needed only 5 attributes? In that case you have one entity that needs to support two DTOs unless you're willing to deal with the normal view ignoring 95 attributes on the product DTO.
Kevin Pang
Assuming a Product is a single Entity, have one DTO support that Entity and make that DTO available as a Product-typed property of the ViewModels for both the admin and normal Views. Usually, a single Entity is a single row in a database. If that's not the case, use lazy loading with your favorite ORM to optimize database queries.
Dave Swersky
+1  A: 

Maybe you could use meta annotations, which puts the attributes on a separate class:

namespace MvcApplication1.Models
{
    [MetadataType(typeof(MovieMetaData))]
    public partial class Movie
    {
    }


    public class MovieMetaData
    {
        [Required]
        public object Title { get; set; }

        [Required]
        [StringLength(5)]
        public object Director { get; set; }


        [DisplayName("Date Released")]
        [Required]
        public object DateReleased { get; set; }
    }
}

Code sample was borrowed from this article.

Morten Mertner
+1  A: 

You might find useful this.

And keep in mind that validation lives everywhere. There is nothing wrong if DTOs applies UI validation (like getting necessary fields filled, datetime in correct format etc.) and domain objects - domain validation (e.g. account has money before withdrawn operation).

You can't create validation universal. Best thing You can do - put it in appropriate places.

And weed that feeling about duplication out. Usage of DTOs usually means applying single responsibility principle. There is no duplication if you got 2 customer objects where one is responsible for carrying business logic and second that is responsible for displaying it.

Arnis L.