2013-12-15 21 views
2

我要定義「說明」屬性上我的模型,用於提示,網格,報告等,以及確認其他&屬性一般用途:MVC Passing models vs viewmodels - 如何保留模型元信息?

public class MyModel 
{ 
    ... 
    [DisplayName("Yo thang")] 
    [Description("This field determines the XYZ blah-de-blah")] // Tooltips 
    [StringLength(100)] // Validation 
    public string CoolThing { get; set; } 
    ... 
} 

在詳細內容/編輯觀點對於爲MyModel,我想「這個字段決定...」自動作爲工具提示,並驗證踢入。

我有這個目前正在運行時,視圖直接給MyModel(幫助函數讀取屬性&連線jQuery的小部件)。

但是,我考慮搬到的ViewModels + AutoMapper,並明確作爲屬性是不是在視圖模型我會失去這個功能:

public class MyViewModel 
{ 
    ... 
    public string CoolThing { get; set; } 
    ... 
} 

我不想把屬性上MyViewModel,因爲許多ViewModel將擁有這個屬性,這將複製信息(非DRY)。

什麼是我的最佳選擇,以保留元信息在一個位置,但保留ViewModels的好處?

回答

0

@MohammadRB &別人,

一些上場後,我周圍有一個解決方案,我很滿意。

在MyViewModel上使用[MetadataType(typeof(MyModel))]不起作用,因爲它需要MyViewModel實現MyModel的所有屬性(這會損失一半的重點)。

相反,我已採取此路徑:

1)創建自定義DataAnnotationsModelMetadataProvider如下所述:

http://geekswithblogs.net/brians/archive/2010/06/14/asp.net-mvc-localization-displaynameattribute-alternatives-a-better-way.aspx

2)創建自定義ModelMetadata屬性(相同的語法MetadataType)

3)在我的自定義元數據提供程序中,我檢查containerType是否定義了[ModelMetadata]。如果是這樣,我查找屬性(如果存在),加載自定義屬性,並將它們concat到enumerable屬性。

完全的源代碼:

public sealed class ModelMetaTypeAttribute : Attribute 
{ 
    public ModelMetaTypeAttribute(Type modelType) 
    { 
     ModelType = modelType; 
    } 

    public Type ModelType { get; private set; } 
} 

public static class ModelMetaTypeUtilities 
{ 
    private static readonly Dictionary<PropertyInfo, ICollection<Attribute>> MetaAttributesCache = new Dictionary<PropertyInfo, ICollection<Attribute>>(); 

    public static ICollection<Attribute> GetMetaAttributes(this PropertyInfo propertyInfo) 
    { 
     // Lookup from cache if possible 
     var key = propertyInfo; 
     if (MetaAttributesCache.ContainsKey(key)) return MetaAttributesCache[key]; 

     //Try the metadataType instead as well 
     ICollection<Attribute> attributes = new List<Attribute>(); 
     var classType = propertyInfo.DeclaringType ?? propertyInfo.ReflectedType; 
     var metadataTypeAttribute = classType.GetCustomAttribute<ModelMetaTypeAttribute>(); 
     if (metadataTypeAttribute != null) 
     { 
      var metadataType = metadataTypeAttribute.ModelType; 

      var metadataPropertyInfo = metadataType.GetProperty(propertyInfo.Name); 
      if (metadataPropertyInfo != null) 
      { 
       attributes = metadataPropertyInfo.GetCustomAttributes().ToList(); 
      } 
     } 

     MetaAttributesCache.Add(key, attributes); 
     return attributes; 
    } 
} 

// For more info see: http://geekswithblogs.net/brians/archive/2010/06/14/asp.net-mvc-localization-displaynameattribute-alternatives-a-better-way.aspx 
public class CustomDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    protected override ModelMetadata CreateMetadata(
     IEnumerable<Attribute> attributes, 
     Type containerType, 
     Func<object> modelAccessor, 
     Type modelType, 
     string propertyName) 
    { 

     var allAttributes = IncludeMetaAttributes(containerType, propertyName, attributes); 

     var meta = base.CreateMetadata(allAttributes, containerType, modelAccessor, modelType, propertyName); 

     return meta; 
    } 

    private static IEnumerable<Attribute> IncludeMetaAttributes(Type containerType, string propertyName, IEnumerable<Attribute> attributes) 
    { 
     var propertyInfo = !propertyName.IsNullOrEmpty() ? containerType.GetProperty(propertyName) : null; 
     if (propertyInfo == null) return attributes; 

     var metaAttributes = propertyInfo.GetMetaAttributes(); 
     return attributes.Concat(metaAttributes); 
    } 
} 

而在的Application_Start:

ModelMetadataProviders.Current = new CustomDataAnnotationsModelMetadataProvider(); 
3

您可以在局部類定義ATTRS:

public partial ModelMetaData 
{ 
    [Description("This field determines the XYZ blah-de-blah")] // Tooltips 
    [StringLength(100)] // Validation 
    public string CoolThing { get; set; } 
} 

,並宣告以MetadataType ATTR和部分模型和視圖模型:

[MetadataType(typeof(ModelMetaData))] 
public partial class Model 
{ 
    public string CoolThing { get; set; } 
} 

[MetadataType(typeof(ModelMetaData))] 
public partial class MyViewModel 
{ 
    public string CoolThing { get; set; } 
} 

這哥們類必須在定義相同的名稱空間。

(我以前從來沒有使用這種方法,但我認爲它會做你想要什麼)

+0

感謝穆罕默德,這當然是一種選擇,但爲了便於開發和簡化對其他開發人員的顯然是很清潔劑可以將元信息直接保存在模型本身上。來想一想...可以MyViewModel有[MetadataType(typeof(MyModel))]? –

+0

@BrendanHill是將元信息放在模型類上會更乾淨,但在你的情況下,我更喜歡這種方法(因爲我不知道另一種方法:)'[MetadataType(typeof(ModelMetaDate))]'''''''' MyViewModel'? – MRB

+0

如果可以使用模型本身的MetadataType,那麼我可以a)將我的屬性保留在我的模型(首選位置)上;和b)只寫模型+視圖模型而不是模型+視圖模型+元模型 - 保持簡單。 –