0

我正在研究的一個項目的關鍵特性之一是用戶可以基於預先存在的字段類型池(衆所周知的類型,類型和類型)來配置表單(如在「表單」中填充)例如「用戶名」,「出生日期」等,還包括「字符串」,「日期時間」等「通用類型」)。如何將MetaData添加到動態構建MVC3 ViewModel?

我們曾經有一個運行良好的「衆所周知」的類型,看起來像這樣的靜態視圖模型:

public class UserInputModel 
{ 
    [StringLength(200)] 
    public string Name { get; set; } 

    [Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))] 
    public DateTime BirthDate { get; set; } 

    //Here comes a lot of other properties 
} 

所有已知的性能進行了上市,我們被顯示或隱藏他們給出的上下文。

但最後的要求來了,並改變了這一切。用戶現在應該能夠添加儘可能多的泛型類型字段。爲了做到這一點,我們決定讓這個InputModel完全動態化。它現在看起來像這樣:

public class UserInputModel 
{ 
    // Each ModelProperty has an "Id" and a "Value" property 
    public ICollection<ModelProperty> Properties { get; set; } 
} 

這工作就像一個魅力。剃刀視圖只需要遍歷集合,創建相應的控件集合的每個屬性在超過標準的方式:

@Html.TextBoxFor(m => m.Properties[index].Value); 

...我們很好地取回數據作爲填好的表格。

=>這工作正常,但我們沒有任何客戶端驗證。爲此,我們需要一些元數據......這是我們沒有通過註釋了,因爲我們正在動態創建模型。

爲了提供這些元數據,我創建了一個CustomModelMetadataProvider,它繼承自DataAnnotationsModelMetadataProvider,並在Global.asax中將其註冊爲新的ModelMetadataProvider。在創建ViewModel時調用CreateMetadata()函數,並且對於ViewModel的每個屬性...都非常好。

問題開始的地方:爲了向當前屬性添加一些元數據,我首先需要確定我目前正在查看哪個屬性(「Name」的最大長度爲200,「出生日期」hasn所以我不能爲每個屬性默認分配最大長度)。還有一些人,我沒有設法做到這一點,因爲所有的財產都有相同的名稱Value和相同的容器類型ModelProperty

我嘗試訪問通過反射屬性的容器,但自從ModelAccessor的目標是視圖模型本身(因爲lambda表達式m => m.Properties的),下面的結構給我的視圖模型作爲一個整體,而不僅僅是ModelProperty:

var container = modelAccessor.Target.GetType().GetField("container"); 
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target); 

我一直在翻轉這一遍又一遍,但無法找到一種方法來確定我手中有哪些ModelProperty。有沒有辦法做到這一點?

更新:經過一段時間翻轉了所有可能的方向之後,我們終於找到了另一條路。我們基本上使用unobstrusive javascript來使用MVC的驗證功能,而無需觸及屬性或元數據。簡而言之,我們將HTML屬性添加到@Html.TextBoxFor()語句中,如value-data="true"(以及所有其他必需的屬性)。這對於所有的原子驗證(需要的,stringlength等)都非常有用。

回答

0

Tim,您可以利用您的屬性通過Ajax與Remote attribute進行客戶端驗證。

基本上,您需要設置一個驗證控制器,然後在該控制器中寫入一些智能。但至少你可以寫一些輔助方法,並將它保留在一個地方。根據您向最終用戶呈現的元數據,您將擁有一系列驗證程序,並且每種驗證程序方法都適用於具有良好重用性的特定類型。

這種方法的一個缺陷是,你需要爲你想要支持的每種類型和條件編寫一個驗證方法。聽起來就像你不得不沿着那條路走下去。

希望這會有所幫助。

+0

感謝您的回答,不幸的是 - 除非我誤解了你 - 我認爲你錯過了這一點。整個問題本身不是驗證,而是注入屬性的元數據。 –

0

看看這篇文章是否對您有所幫助:Technique for carrying metadata to View Models with AutoMapper

還可以使用這一個想法(自定義模型元數據提供商):changing viewmodel's MetadataType attribute at runtime

Fluent validation可能是你在我心中是最好的選擇,但它顯然是由你來選擇高於之間的最佳匹配。

更新

嘗試使用ModelMetadata並覆蓋ModelMetadataProviderDive Deep Into MVC: ModelMetadata and ModelMetadataProvider。通過這種方式,您可以完全自定義模型元數據(取代數據註釋),並且可以完全控制正在發生的事情,而不依賴於ASP.NET MVC。另一個好地方是Creating your own ModelMetadataProvider to handle custom attributes

希望這一切對你有所幫助。

+0

感謝您的回答。關於第一個鏈接,作者似乎仍然使用PropertyName作爲鑑別器......這正是我無法做到的(我所有的屬性都稱爲「Value」)。關於第二個鏈接,他們使用屬性的類型來區分它...但是同樣,我所有的同類屬性... –

+0

「流暢驗證」如何?我知道(我沒有用過它)很多人都做了,並且相當成功,並讚揚了它的大好時機。嘗試採用完全不同的方法:重寫(提供自己的)'ModelMetadataProvider'。查看我答案中的更新。 –

+0

我也沒有使用Fluent驗證,但據我所知,它使用依賴屬性類型的lambda表達式...所以這再次不適合我。關於你的更新,這正是我正在做的;我創建了我的CustomModelMetadataProvider,並試圖修改事物流。這正是我遇到一些問題的原因,因爲我無法根據其名稱或其類型來識別屬性... –

相關問題