2012-08-15 18 views
0

有一類(精簡版):在運行時服務器端驗證添加ValidationAttribute取決於另一個容器屬性

public class Parameter 
{ 
    public Guid Id { get; set; } 

    public decimal Value { get; set; } 
} 

在我看來,我有參數的字典,他們得到呈現:

<input ... name="Parameters[3].Key" type="hidden" value="UniqueParamName" /> 
<input ... name="Parameters[3].Value.Id" type="hidden" value="395816ad-dfde-11e1-8c36-848f69f05f09" /> 
<input ... name="Parameters[3].Value.Value" type="text" value="75" /> 

驗證規則將由用戶通過一些GUI設置並存儲在數據庫中。 我想從Parameter.IdParameter.Value數據庫中獲得ValidationAttribute s,但是我看不到任何做法。 我也嘗試添加ModelMetadataProvider.CreateMetadata中的屬性,其中容器可以通過一些[討厭的]反射來訪問,但是當爲「值」創建元數據時(尚不可靠),「Id」還沒有被分配。 也許我太過於複雜,我只想堅持內置的驗證。

public class ExtendedValidationProvider : DataAnnotationsModelValidatorProvider 
{ 
    protected override IEnumerable<ModelValidator> GetValidators(
     ModelMetadata metadata, 
     ControllerContext context, 
     IEnumerable<Attribute> attributes) 
    { 
     if (metadata.ContainerType == typeof(Parameter) 
      && metadata.PropertyName == "Value") 
     { 
      Guid parameterId = <some magic code>; 
      IEnumerable<Attribute> validationAttributes 
       = db.GetValidationAttributesByParameterId(parameterId); 
      return base.GetValidators(metadata, context, validationAttributes); 
     } 

     return Enumerable.Empty<ModelValidator>(); 
    } 
} 

回答

0

我想我可以在自定義ModelMetadataProvider這樣設置容器:

public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, 
    Type containerType, string propertyName) 
{ 
    var metadata = _InnerProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName); 
    if (containerType == typeof(Parameter) 
     && !metadata.AdditionalValues.ContainsKey("container")) 
    { 
     metadata.AdditionalValues["container"] = GetContainer(modelAccessor); 
    } 

    return metadata; 
} 

GetContainer是使用[討厭]反射(編譯和高速緩存表達,實際上)的方法。

最後,對驗證提供者的一側沒有魔碼:

public class ExtendedValidationProvider : DataAnnotationsModelValidatorProvider 
{ 
    protected override IEnumerable<ModelValidator> GetValidators(
     ModelMetadata metadata, 
     ControllerContext context, 
     IEnumerable<Attribute> attributes) 
    { 
     if (metadata.ContainerType == typeof(Parameter) 
      && metadata.PropertyName == "Value") 
     { 
      Guid parameterId = ((Parameter)metadata.AdditionalValues["container"]).Id; 
      IEnumerable<Attribute> validationAttributes 
       = db.GetValidationAttributesByParameterId(parameterId); 
      return base.GetValidators(metadata, context, validationAttributes); 
     } 

     return Enumerable.Empty<ModelValidator>(); 
    } 
} 
0

在我看來,你應該使用模型驗證。模型驗證將根據您的模型以及在模型上定義的驗證屬性應用的規則進行驗證。

public class MyModel 
{ 
    // This model uses model validation 

    [Required(ErrorMessage = "FirstName is a required field.")] 
    [StringLength(50, ErrorMessage = "Your FirstName can not exceed 50 characters.")] 
    public string FirstName { get; set; } 

    [Required(ErrorMessage = "LastName is a required field.")] 
    public string LastName { get; set; } 
} 

這建立了您的驗證模型。然後在您的控制器/操作中,您需要使用ModelState.IsValid來驗證您的ModelState。您也可以在控制器中進行一些自定義的「驗證」,並使用型號AddModelError添加自定義錯誤。

如果您想進一步創建自己的驗證屬性,那麼您只需創建一個新的類,該類繼承自類ValidationAttribute。這將允許您根據自己的DAL層中的值或與綁定到模型的其他值進行驗證。

如果您需要使用全球化,使用模型驗證還可以很好地(並且很容易地)設置您的屬性,這將允許您使用資源字符串爲您可能已定義的各種語言選擇資源文件。

我正在從內存中做這件事,但這應該引導您正確使用MVC3的內置功能並利用模型綁定和模型狀態。

HTH

+0

我的驗證規則是通過用戶界面來設置後來從數據庫加載,這就是爲什麼我題目用語言這個問題「在運行時「。猜猜我應該說清楚。 – rgripper 2012-08-15 20:55:59

+0

是的,這仍然適用。您仍然可以編寫一個ValidationAttribute來完成自定義驗證規則查找(從數據庫等),然後將此自定義屬性放置在您的模型上。 – Sean 2012-08-15 22:00:19

+0

我不能把它放在我的模型上,因爲你建議每個類型的基礎上,我需要它不同的'參數'的每個實例, – rgripper 2012-08-16 16:05:33

相關問題