Entity Framework 6 Reusing Data Annotations

I was looking for some time to finally resolve this issue, but have not yet come to a conclusion. I would like to specify data annotations only once in the data model class, and they can be seen in the user interface from the view model class without specifying them again. To illustrate my point, suppose I have a UserAccount class as such ...

public class UserAccount
{
    [Display(Name = "Username", Prompt = "Login As"), Required()]
    string UserName { get; set; }
    [Display(Name = "Password", Prompt = "Password"), Required(), DataType(DataType.Password), StringLength(255, MinimumLength = 7, ErrorMessage = "The password must be at least 7 characters")]
    string Password { get; set; }
}

Now I would like to specify a view model containing a password confirmation field that will not be stored in the database and potentially other data models, but I do not want to specify all the data annotation attributes again. It is an attempt to find the best practice, but a multiple declaration is also required, and at some point it will be amended and others will not.

I reviewed the Interfaces / Inheritance solution, but it didn’t solve it in different ways for various reasons. Another potential solution might be to have a View Model class (model) attribute to say inherit attributes from ... but I still can't find anything suitable for this.

Has anyone got any bright ideas or applied it appropriately?

+4
source share
4 answers

Here is a solution that I came up with when considering other possible solutions. This is based on finding the following article ...

http://jendaperl.blogspot.co.uk/2010/10/attributeproviderattribute-rendered.html

My reasons for this over others are indicated at the bottom of this post.

Data Model...

public class UserAccount
{
     [Display(Name = "Username", Prompt = "Login As"), Required()]
     string UserName { get; set; }
     [Display(Name = "Password", Prompt = "Password"), Required(), DataType(DataType.Password), StringLength(255, MinimumLength = 7, ErrorMessage = "The password must be at least 7 characters")]
     string Password { get; set; }
}

, , , , , , , , . . , ...

using System.ComponentModel;

namespace MyApp.ViewModels
{
    public class AttributesFromAttribute : AttributeProviderAttribute
    {
        public AttributesFromAttribute(Type type, string property)
            : base(type.AssemblyQualifiedName, property)
        {
        }

        public T GetInheritedAttributeOfType<T>() where T : System.Attribute
        {
            Dictionary<string,object> attrs = Type.GetType(this.TypeName).GetProperty(this.PropertyName).GetCustomAttributes(true).ToDictionary(a => a.GetType().Name, a => a);
            return attrs.Values.OfType<T>().FirstOrDefault();
        }

    }
}

...

[AttributesFrom(typeof(MyApp.DataModel.UserAccount), "UserName")]

...

public class RegisterViewModel
{
    public UserAccount UserAccount { get; set; }
    public RegisterViewModel()
    {
        UserAccount = new UserAccount();
    }

    [AttributesFrom(typeof(MyApp.DataModel.UserAccount), "UserName")]
    string UserName { get; set; }
    [AttributesFrom(typeof(MyApp.DataModel.UserAccount), "Password")]
    string Password { get; set; }

    [AttributesFrom(typeof(MyApp.DataModel.UserAccount), "Password")]
    [Display(Name = "Confirm Password", Prompt = "Confirm Password"), Compare("Password", ErrorMessage = "Your confirmation doesn't match.")]
    public string PasswordConfirmation { get; set; }

}

, ( PasswordConfirmation ), , GetInheritedAttributeOfType. ...

public static class AttrHelper
{
   public static T GetAttributeOfType<T>(this ViewDataDictionary viewData) where T : System.Attribute
    {
        var metadata = viewData.ModelMetadata;
        var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
        var attrs = prop.GetCustomAttributes(false);

        // Try and get the attribute directly from the property.
        T ret = attrs.OfType<T>().FirstOrDefault();

        // If there isn't one, look at inherited attribute info if there is any.
        if(ret == default(T))
        {
            AttributesFromAttribute inheritedAttributes = attrs.OfType<AttributesFromAttribute>().FirstOrDefault();
            if (inheritedAttributes != null)
            {
                ret = inheritedAttributes.GetInheritedAttributeOfType<T>();
            }
        }

        // return what we've found.
        return ret;
    }
}

, ...

var dataTypeAttr = AttrHelper.GetAttributeOfType<DataTypeAttribute>(ViewData);

viewmodel, , , GetInheritedAttributeOfType.

, ...

  • , DataAnnotations , datamodels .

  • MetadataType , , MetadataType ViewModel.

  • , . , DataModel .

+1

viewmodel atttribute:

[MetadataType(typeof(YourModelClass))]
public class YourViewModelClass
{
   // ...
}

, , .

. MSDN.

. MDSN , . , : ViewModel . , , viewmodel. "" "" buddy.

: Hoots , , EF MVC, . Hoots , .

+4

Interfaces/Inheritance, - .

, ?

:

public class UserAccount : PasswordModel
{
    [Display(Name = "Username", Prompt = "Login As"), Required()]
    public string UserName { get; set; }

    [Display(Name = "Password", Prompt = "Password")]
    [StringLength(255, MinimumLength = 7, ErrorMessage = "The password must be at least 7 characters")]
    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
}

public class ResetPasswordViewModel : PasswordModel
{
    [Display(Name = "Retype Password", Prompt = "Password")]
    [Required]
    [DataType(DataType.Password)]
    [CompareAttribute("Password", ErrorMessage = "Password does not match")]
    string RetypePassword { get; set; }
}

UPDATE:

M-V-C M- VM -V-C

ViewModel

VM ViewModels. , , . .

ViewModels

ResetPasswordViewModel ViewModel, . RetypePassword, ViewModel EF.

. . .

public class ResetPasswordViewModel
{
    public UserAccount UserAccount { get; set; }

    [Display(Name = "Retype Password", Prompt = "Password")]
    [Required]
    [DataType(DataType.Password)]
    public string RetypePassword { get; set; }
}

ViewModel Password. , :

@Model.UserAccount.Password
@Model.ResetPassword

, ViewModels. .

+2

... , ... . , - , - , , , , - , 100% .

.. .. . ...

, , , , . , - .

, , , . , , .

, , . , .

+1
source

Source: https://habr.com/ru/post/1538716/


All Articles