问题概述:
我希望在我的表单中有一些条件逻辑。用户使用单选按钮进行选择,根据选择,我想隐藏一些字段并显示其他字段。这也应该影响验证(不应该验证隐藏字段)。我认为这是一个典型的问题,但我找不到任何例子,我自己的解决方案似乎有很多管道。
我的实际问题:
让我们从viewmodel类开始(根据这个问题的需要稍微简化):
public class Scenario
{
public Request Request { get; set; }
public Response Response { get; set; }
// … some other properties
}
public class Request
{
//some properties
}
public class Response
{
[Required]
public string ResponseType { get; set; }
[Required]
public string State { get; set; }
[Required]
[NotZero] //this is my custom validation attribute
public string ErrorCode { get; set; }
public string ErrorDescr { get; set; }
}
在Scenario
模型的创建/编辑视图中,我有一个由3个标签组成的相当大的表单。在第3个选项卡上,我显示基于Response
模型的局部视图。这是我想要条件逻辑的地方。 ResponseType
属性是表单上的单选按钮。它可以有两个值:NORMAL和ERROR。在出现错误的情况下,我想显示并验证ErrorCode
和ErrorDescr
属性。在NORMAL的情况下,我想只显示和验证State
属性。
我的解决方案:
在Scenario控制器中,我有这样的代码:
public ActionResult Edit(int id, Scenario scenario)
{
Response response=scenario.Response;
if (response.ResponseType != null)
{
if (response.ResponseType == "NORMAL")
{
//in this case remove validation for errorcode
this.ModelState.Remove("Response.ErrorCode");
}
else
{
//in this case remove validation for state
this.ModelState.Remove("Response.State");
}
}
if (ModelState.IsValid)
{
//map to entity and save to database
}
}
这是一大堆丑陋的管道(尤其是控制器代码 - 使用字符串键从ModelState中删除项目......没有类型安全等),肯定必须有更好的方法吗? < / p>
答案 0 :(得分:1)
您可以尝试继承IValidateableObject
课程中的Response
并在Validate
中执行条件验证。像这样:
public class Response : IValidateableObject
{
[Required]
public string ResponseType { get; set; }
public string State { get; set; }
public string ErrorCode { get; set; }
public string ErrorDescr { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ResponseType == "NORMAL")
{
if (State.IsNullOrWhiteSpace)
yield return new ValidationResult("State is required", new [] { "State" });
}
// additional validations...
}
}
答案 1 :(得分:0)
现在已经很老了,我不喜欢这个没有答案的闲逛,所以我会自己回答。
正确的解决方案是实现自定义验证属性,并且还实现IClientValidatable接口。这满足了所有要求-控制器内部没有管道,并且客户端验证始终如一。
如今,我可能甚至自己也不会实现该功能-我将使用ExpressiveAnnotations之类的现有库,该库提供了一个不错且灵活的RequiredIf属性:
public class Response
{
[Required]
public string ResponseType { get; set; }
[RequiredIf("ResponseType == 'NORMAL'"]
public string State { get; set; }
[RequiredIf("ResponseType == 'ERROR'"]
public string ErrorCode { get; set; }
public string ErrorDescr { get; set; }
}
通过在Global.asax上添加几行并包括带有验证器的javascript,对其进行配置后,该属性在服务器端和客户端均可以使用。您可以在项目页面上阅读详细信息。