使用ModelState.IsValid

时间:2016-06-19 12:41:12

标签: c# asp.net-mvc controller modelstate

我已经和MVC一起开发了几年了,有人认为我最初的教学是HttpPost行动,第一的事情总是< / strong> do是对ModelState.IsValid执行检查,所以......

[HttpPost]
public ActionResult Edit(ViewModel form) {
    if(ModelState.IsValid) {
        // Do post-processing here
    }
}

我现在遇到一个问题,我在表单中传递了哈希ID。如果它为0,则为新记录,如果其高于0则表示我正在编辑。如果我的ModelState.IsValid返回false,我需要再次设置一些下拉列表数据,然后返回到具有相同模型的Edit视图。要设置失败后返回到表单的其中一些项目,我需要知道未散列的数字,但在ModelState.IsValid中取消它会使它在else语句中不可用。

因此,执行以下操作是否可以接受: -

[HttpPost]
public ActionResult Edit(ViewModel form) {
    int myID = 0;
    if(/** unhashing is successful...**/)
    {
        if(ModelState.IsValid) {
            // Do post-processing here
        }
        else 
        {
            // Setup dropdowns using unhashed ID and return original view...
        }
    }
}

请注意,ModelState.IsValid不是HttpPost中的第一个测试。那可以接受吗?如果没有,是否有更合适的方式来做这样的逻辑?

谢谢!

1 个答案:

答案 0 :(得分:1)

在您的来源中,您似乎已经写了一些关于 unhashing 的评论,但这样的术语并不存在。散列函数的目的是不可逆转的。我认为另一方面,你的意思是解密查询字符串值。理想情况下,此解密应在视图模型的自定义模型绑定器中进行,并将此参数的ModelState.IsValid值设置为false。因此,在控制器操作中,您需要检查的是此布尔参数。控制器操作不应解密任何查询字符串或任何参数。这应该在MVC执行管道中更早地完成。自定义模型绑定器甚至自定义授权过滤器更适合此方案。

让我们举个例子:

public class ViewModel
{
    public int Id { get; set; }

    ... some other stuff around
}

现在您可以为此视图模型编写自定义模型绑定器:

public class MyDecryptingBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        if (propertyDescriptor.Name == "Id")
        {
            var idParam = bindingContext.ValueProvider.GetValue("Id");
            if (idParam != null)
            {
                string rawValue = idParam.RawValue as string;
                int value;
                if (this.DecryptId(rawValue, out value))
                {
                    propertyDescriptor.SetValue(bindingContext.Model, value);
                    return;
                }
            }
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }

    private bool DecryptId(string raw, out int id)
    {
        // TODO: you know what to do here: decrypt the raw value and 
        // set it to the id parameter, or just return false if decryption fails
    }
}

现在,您可以在引导时(Application_Start)向视图模型注册此自定义模型绑定器:

ModelBinders.Binders.Add(typeof(ViewModel), new MyDecryptingBinder());

然后您的控制器操作将如下所示:

[HttpPost]
public ActionResult Index(ViewModel model)
{
    if (ModelState.IsValid)
    {
        // The decryption of the id parameter has succeeded, you can use model.Id here
    }
    else
    {
        // Decryption failed or the id parameter was not provided: act accordingly

    }
}