11

If you read this article on Validation with the Data Annotation Validators, it shows that you can use the MetadataType attribute to add validation attributes to properties on partial classes. You use this when working with ORMs like LINQ to SQL, Entity Framework, or Subsonic. Then you can use the "automagic" client and server side validation. It plays very nicely with MVC.

However, a colleague of mine used an interface to accomplish exactly the same result. it looks almost exactly the same, and functionally accomplishes the same thing. So instead of doing this:

[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; }
}

He did this:

public partial class Movie :IMovie
{
}

public interface IMovie
{
    [Required]
    object Title { get; set; }

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


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

So my question is, when does this difference actually matter?

My thoughts are that interfaces tend to be more "reusable", and that making one for just a single class doesn't make that much sense. You could also argue that you could design your classes and interfaces in a way that allows you to use interfaces on multiple objects, but I feel like that is trying to fit your models into something else, when they should really stand on their own. What do you think?

John B
  • 20,062
  • 35
  • 120
  • 170

3 Answers3

3

I like your interface approach as it allows you to define a contract for your model which you can use to adapt your ORM generated classes to. That would allow you to decouple your app from the ORM framework and get more use out of the MetadataType interface as it serves as data validation metadata as well as a contract for your model. You could also decorate your interface with serialization attributes for use in WCF gaining more use out of the interface. I followed a few early blogs that recommended creating a metadata class but again I think the interface solution is a nice idea.

Athens Holloway
  • 2,183
  • 3
  • 17
  • 26
  • I agree. Actually the data annotations have always made me feel uneasy because I have felt that as UI stuff putting them on the model violated separation of concerns. Using annotated interfaces goes a long way to addressing those concerns. – Christopher Edwards Jun 29 '10 at 11:04
2

If those two options are the two I am presented with, I would personally probably choose the interface way, simply because I think it looks cleaner. But this is entirely based on personal taste - I don't know enough about the inner workings of .NET to say for sure, but I don't know any case where the actual functionality of the two approaches would differ.

On the other hand, a much better approach would be to use Data Transfer Objects (DTO's) for sending data back and forth, and have the validation requirements on them. That is, instead of requiring that the Movie object meet all the validation requirements, you require that a MovieInput object meets all those requirements, and then create code to map a correct MovieInput into a Movie. (If you don't want to do that manually, you could use AutoMapper or some other utility).

The concept is basically to have something like a View Model object on the way in just as well as on the way out - I could just as well have let MovieInput be called MovieViewModel and use it for transferring of data both in and out of the server.

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • So if you had a facade between the UI and "persistence" layer, and you solely doled out these DTOs to the views, where do you put and integrate the more complex validation (business rules)? Implement `IValidateableObject` in the DTOs? That seems wrong... because all in all, we want to tie it all back to the UI using the integration points MVC provides (and dataannotations and ivalidateableobject could be used outside MVC too). – kamranicus Mar 22 '11 at 20:07
  • @subkamran: I see two possible scenarios here. 1) You need exactly the same input regardless of UI. In this case, the UI layer should be required to instantiate a common DTO, where the validation rules can be enforced, and the DTO can be used regardless of UI layer. 2) Input will be different in different UI layers to produce the same type of object in the business layer. In this case, you'll need UI specific DTO's, but the validation rules can still be enforced on the DTO - since the input requirements are different, the validation rules are as well. So you can always validate on your DTO's. – Tomas Aschan Mar 22 '11 at 23:38
  • I understand your logic and it makes sense, but won't I lose, say, all the Javascript integration? Because more often than not, my views deal with a subset of the object's properties (a DTO) but also with unrelated properties solely for the view (say a look up dictionary for select lists). So I can't really accept those as inputs from my service because they have needless properties I don't care about. Possibly, I could inherit from these DTOs, and create ViewModels off of them for MVC view consumption. That just creates more objects floating around but maybe that's fine? – kamranicus Mar 23 '11 at 12:22
1

I see no functional difference between the two approaches. I'm not sure reusability is really important here, given that validation will most often be on "one-off" ViewModels that probably won't get much, if any, reuse.

Dave Swersky
  • 34,502
  • 9
  • 78
  • 118