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);
T ret = attrs.OfType<T>().FirstOrDefault();
if(ret == default(T))
{
AttributesFromAttribute inheritedAttributes = attrs.OfType<AttributesFromAttribute>().FirstOrDefault();
if (inheritedAttributes != null)
{
ret = inheritedAttributes.GetInheritedAttributeOfType<T>();
}
}
return ret;
}
}
, ...
var dataTypeAttr = AttrHelper.GetAttributeOfType<DataTypeAttribute>(ViewData);
viewmodel, , , GetInheritedAttributeOfType.
, ...
, DataAnnotations , datamodels .
MetadataType , , MetadataType ViewModel.
, . , DataModel .