5

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.

Kevin Pang
  • 41,172
  • 38
  • 121
  • 173

3 Answers3

3

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
  • 34,502
  • 9
  • 78
  • 118
  • 1
    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 Apr 03 '10 at 15:06
  • 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 Apr 03 '10 at 15:08
  • 1
    DTO's are bags for your data, the ViewModel is the place to mix & match. I don't think it's a good idea to have multiple DTO's with varying data, that gets into the mess you rightly don't want to have to maintain. – Dave Swersky Apr 03 '10 at 16:18
  • 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 Apr 03 '10 at 18:26
  • 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 Apr 03 '10 at 20:34
  • 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 Apr 04 '10 at 17:05
  • 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 Apr 04 '10 at 17:16
  • @Dave Swersky I would disagree with beating this drum since there is not rule that DTOs are restricted to flattened data. Having a restriction like this does not make sense in a lot of scenarios. Let's not access all fields every time you query a few fields from an entity. DTOs are simply containers for transferring data. You can use these DTOs within your ViewModel. – jwize Jul 26 '16 at 00:16
  • I recommend not using DTOs as a ViewModel but rather decorate you VM with them, and would use inheritance in your DTOs to organize them per ViewModel. I would also recommend using attributes in your classes rather than on a MetadataType classes since these objects are dumb and refactoring gets more challenging if you separate concerns here. – jwize Jul 26 '16 at 00:17
3

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.

Community
  • 1
  • 1
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
1

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
  • 9,414
  • 4
  • 39
  • 56
  • While, I may be incorrect in saying this, I recommend using Metadata in DTO classes and not outside. as mentioned in my comments above. I would however put them into a metadata type if I was binding directly to my Entity Framework layer on a simple project and/or use the fluent API. – jwize Jul 26 '16 at 00:21