2011-10-12 34 views
11

验证模型时需要使用模型外部的信息以验证模型,验证模型的好方法是什么?例如,考虑下面的模型:然后ASP.NET MVC 3:在需要模型外部的信息时验证模型

public class Rating { 
    public string Comment { get; set; } 
    public int RatingLevel { get; set; } 
} 

系统管理员可以设置所需要注释的RatingLevels。这些设置可通过设置服务获得。

因此,为了充分验证模型,我需要外部信息,在这种情况下,设置服务。

我认为到目前为止以下:

  1. 注入服务到模型中。DefaultModelBinder使用System.Activator来创建对象,所以它不会通过正常的依赖关系解析器,我不能将该服务注入到模型中而不创建新的模型绑定器(除此之外,这并不像是正确的方式去了解它)。
  2. 将服务注入到注释中。我不确定这是可能的,但会很快进行调查。它仍然感觉笨拙。
  3. 使用自定义模型绑定器。显然我可以实现OnPropertyValidating做自定义属性验证。尽管我还不确定如何去做,但这似乎是迄今为止最优选的。

上面哪种方法最适合这种验证问题?

回答

14

选项1不适合。它将工作的唯一方法是通过服务定位器反模式拉入依赖项。

选项2 不起作用 尽管由于C#属性要求我无法看到这是如何实现的,但这是可能的。请参阅参考以下内容:

方案3:我不知道这个较早,但似乎是写验证是一个非常强大的方式使用ModelValidator类和相应的ModelValidatorProvider

首先,创建自定义ModelValidatorProvider:

public class CustomModelValidatorProvider : ModelValidatorProvider 
{ 
    public CustomModelValidatorProvider(/* Your dependencies */) {} 

    public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) 
    { 
     if (metadata.ModelType == typeof(YourModel)) 
     { 
      yield return new YourModelValidator(...); 
     } 
    } 
} 

ASP.NET MVC的IDependencyResolver将试图解决上述供应商,所以只要它与你的IoC容器注册,您不需要做任何事其他。然后ModelValidator:

public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator 
{ 
    public EntryRatingViewModelValidatorMvcAdapter(
      ModelMetadata argMetadata, 
      ControllerContext argContext) 
       : base(argMetadata, argContext) 
    { 
     _validator = validator; 
    } 


    public override IEnumerable<ModelValidationResult> Validate(object container) 
    { 
     if (/* error condition */) 
     { 
      yield return new ModelValidationResult 
       { 
       MemberName = "Model.Member", 
       Message = "Rating is required." 
       }; 
     } 
    } 
} 

由于供应商通过IDependencyResolver检索和提供者拥有返回ModelValidator的I很容易能够注入的依赖关系和进行必要的验证完全控制。

+0

我正在使用MVC5,但我认为上面它仍然相关。你说过“MVC的IDependencyResolver会尝试解决提供者”。但是,您将如何向IoC容器注册提供者? (在我的情况下统一)。 – Ben

1

假设您希望基于从服务返回的值对模型进行客户端和服务器端验证,我会选择2.,将服务注入注释

我在this question about adding validators to a model的回复中给出了一些示例代码。您案例中唯一的额外步骤是您需要将您的服务注入您的继承自DataAnnotationsModelValidatorProvider的课程中。

0

只是简单地使用IValidateableObject并在该方法中确定验证是否合适并在那里设置错误?

How do I use IValidatableObject?

+0

为了使模型自行验证,需要访问设置服务。除非我使用service-locator反模式,否则我需要创建一个自定义模型绑定器来将服务注入到模型中,以便它可以进行验证,但没有一个感觉正确。 –

4

你可以尝试fluent validation。它支持asp.net mvc和DI,因此您可以将外部服务注入验证器。

+0

看起来他们确实做得很好。感谢您的链接! –