Is it possible to reuse the DataAnnotations in ViewModel?

懵懂的女人 提交于 2019-12-03 20:35:14

You can create a new buddy class which holds all metadata about properties and class.

public partial class IssueMetadata
{
    [Required(ErrorMessage = "Required")]
    [Display(Name = "Project Number")]
    public int ProjectID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Issue Definition")]
    public string Description { get; set; }
}

Then, we must tell the MVC Framework about the buddy class through the MetadataType attribute, which takes the type of the buddy class as its argument. Buddy classes must be defined in the same namespace and must also be partial classes.

[MetadataType(typeof(IssueMetadata))]
public partial class IssueViewModel
{
      //...

      public int ProjectID { get; set; }
      public string Description { get; set; }

      //...
}

[MetadataType(typeof(IssueMetadata))]
public partial class Issue
{
      [Key] 
      public int ID { get; set; }

      public int ProjectID { get; set; }
      public string Description { get; set; }

      //... removed for brevity

      //Navigation Properties:
      public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}

Additional note:
If IssueMetadata and Issue (or IssueViewModel) classes located in different assemblies, then you can associate classes with their buddy class in runtime, like that:

public class AssociatedMetadataConfig
{
    public static void RegisterMetadatas()
    {
        RegisterPairOfTypes(typeof(Issue), typeof(IssueMetadata));
        RegisterPairOfTypes(typeof(IssueViewModel), typeof(IssueMetadata));
    }

    private static void RegisterPairOfTypes(Type mainType, Type buddyType)
    {
        AssociatedMetadataTypeTypeDescriptionProvider typeDescriptionProvider 
          = new AssociatedMetadataTypeTypeDescriptionProvider(mainType, buddyType);

        TypeDescriptor.AddProviderTransparent(typeDescriptionProvider, mainType);
    }
}

And, just call this static method in global.asax:

AssociatedMetadataConfig.RegisterMetadatas();

@StephenMuecke is right. DomainModel attributes and ViewModel attributes are different and you can use them seperately in your models. But I would use inheretence in this case, if I were you. You can create a Partial class for ViewModel and inherit your DomainModel from this ViewModel class.

Like:

public class IssueVM
{
    [Key] 
    public int ID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Project Number")]
    public int ProjectID { get; set; }

    [Required(ErrorMessage = "Required")]
    [Display(Name = "Issue Definition")]
    public string Description { get; set; }

    //... removed for brevity

    //Navigation Properties:
    public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}

public class IssueDM : IssueVM
{
    // Other Fields
}

That way you have a base class of ViewModel (less fields) and a larger class with more fields for DB operations. Your ViewModel data annotation attributes are also inherited in your DomainClass that way.

I don't claim that this is the best way, but I'am using this and works fine.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!