我有一个局部视图,它显示了基于视图模型的许多输入。在某些情况下,部分视图不呈现其中的一些输入,但在视图模型中仍然使用[Required]
属性进行装饰。结果,当表单发送回我的控制器时,ModelState.IsValid
返回false。有办法绕过这个吗?
您可以使用Foolproof有条件地验证您的字段。这样,它们只在需要的时候才会被需要,就像你在链接的例子中看到的那样。
private class Person
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public bool Married { get; set; }
[RequiredIfTrue("Married")]
public string MaidenName { get; set; }
}
在本例中,MaidenName
只会在Married == true
ModelState.IsValid
更改为false我建议将验证与基本模型分开。
public class MyModel
{
public string MyString { get; set; }
public string MyHiddenField { get; set; }
}
public interface IMyModel_ValidateMystringOnly
{
[Required]
string MyString { get; set; }
}
[MetadataType(TypeOf(IMyModel_ValidateMystringOnly))]
public class MyModel_ValidateMystringOnly : MyModel
这允许您创建任意数量的验证类型,并且只在需要时验证您想要的。
public ActionResult ShowMyModel()
{
var model = new MyModel(); // or Respository.GetMyModel() whatever..
View(model);
}
public ActionResult ValidateModel(MyModel_ValidateMystringOnly model)
{
if (ModelState.IsValid)
{
// Hey Validation!
}
// MyModel_ValidateMyStringOnly is a MyModel
// so it can be passed to the same view!
return View("ShowMyModel", model);
}
这只是一个示例,但是应该清楚如何在有或没有验证的情况下重用相同的模型。
我有时会在表单根据特定的下拉按钮或单选按钮选择略有变化的情况下使用方法。
在检查ModelState.IsValid
之前,可以在Action方法中执行ModelState.Remove("Object.PropertyName")
注意:属性名应该与呈现给客户端的ID相同。
If isSomeCondition Then
ModelState.Remove("Property1")
ModelState.Remove("Property2")
End If
If ModelState.IsValid() Then
...
End If
您应该始终将VIEW模型与DOMAIN模型分开。这有一个很好的理由,它与安全有关。当您使用域模型作为视图模型时,您很容易受到overposting和/或underposting攻击。您可以在以下页面了解更多信息:
- http://odetocode.com/blogs/scott/archive/2012/03/12/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx
- http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx
- https://hendryluk.wordpress.com/tag/asp-net-mvc/
简而言之,如果你不需要一个字段,那么它就不应该出现在视图模型中。您应该将视图模型转换映射到域模型。尽管它可能很繁琐,但它使您的应用程序更加安全。您可以使用一些库来帮助您进行映射,例如Automapper。
编辑:因为我原来的答案,我得出的结论是,处理这种类型的场景最简单的方法是让你的视图模型实现IValidatableObject接口,然后在Validate方法中编写你的验证逻辑。它不给你客户端验证,但它是最有效和干净的方式来完成自定义/基于场景的验证,而不需要编写自己的自定义过滤器。
您可以在这里阅读更多信息:http://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3