【问题标题】:In ASP.Net MVC, can ModelState be used with an ajax update?在 ASP.Net MVC 中,可以将 ModelState 与 ajax 更新一起使用吗?
【发布时间】:2010-12-25 08:04:56
【问题描述】:

这是我之前收到的关于将错误传递回客户端的previous question 的后续,但也与 ModelState 相关。

有没有人成功地使用了 Nerd Dinner 方法,但使用了 Ajax?因此,Nerd Dinner 进行了更新。

[AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection formValues) 
{
    Dinner dinner = dinnerRepository.GetDinner(id);
    try 
    {
        UpdateModel(dinner);
        dinnerRepository.Save();
        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch 
    {
        foreach (var issue in dinner.GetRuleViolations()) {
        ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
    }
        return View(dinner);
    }
}

使用 jQuery $.ajax

function hijack(form, callback, errorFunction, format) {
    $.ajax({
        url: form.action,
        type: form.method,
        dataType: format,
        data: $(form).serialize(),
        success: callback,
        error: function(xhr, textStatus, errorThrown) {
            errorFunction(xhr, textStatus, errorThrown);
        }
    });
}

Ajax,控制器的“try”部分变成了

    try 
{
    UpdateModel(dinner);
    dinnerRepository.Save();
    return PartialView("PartialDetails", new { id=dinner.DinnerID });
}

,但是你如何处理 catch 部分?

发回错误的简单错误处理解决方案是

catch(Exception ex)
{
    Response.StatusCode = 500;                
    return Content("An Error occured.");
    //throw ex;
}

,但它不会通过内置于 MVC 中的健壮模型状态。我想了很多选择,但我真的想要两件事:

  1. 我希望在 jQuery 的错误属性中处理错误。
  2. 我想尽可能使用内置的 ASP.Net MVC 验证逻辑。

这可能吗?如果不是,您知道的最佳替代方案是什么?

非常感谢。

更新 我还没有将此标记为已回答,因为我还没有实现我认为最有效的方法。

我已经决定我不太喜欢成功 => 发送刷新列表,失败 => 发送我正在采用的错误消息方法。我这样做是为了减少调用次数,但是页面上确实设置了一个刷新的列表。尝试两者都将弹出窗口紧密绑定到其整个页面。

我将添加一个自定义 jQuery 事件,在对话框关闭时刷新母版页列表。本质上,它是观察者模式。我喜欢页面对弹出窗口说“完成后告诉我”(又名关闭)的想法,而不必告诉弹出窗口原因。它确实需要额外的调用,但我不认为这是一个大问题。

我仍然不确定我喜欢/不喜欢服务器端验证的程度,我正在考虑仅使用客户端验证。虽然服务器端验证看起来像是干净的分层,但它也存在许多问题,包括:

1) 它将质量检查放在最后,而不是开始。与制造类似,汽车在到达经销商处进行测试,而不是在制造过程中的点进行测试。
2)它违反了Ajax的意图。 Ajax 不仅仅是发送异步事件,它也是只发送我需要的东西,只接收我需要的东西。发回整个模型状态以提供错误详细信息似乎不适用于 Ajax。

我正在考虑只进行客户端验证,但服务器代码和自定义视图模型可用于告诉客户端如何动态创建这些验证规则。

我还怀疑 IronRuby 或 IronPython 这样的动态语言可能会提供一种更优雅的方式来解决这些问题,但我可能需要更长的时间才能研究这种可能性。

【问题讨论】:

  • 嗯,我认为这真的取决于场景,如果做 2 个请求不是问题,我会去做。个人在客户端使用 JavaScript 进行大量验证并不是我喜欢的事情(我不知道为什么,但我认为 js 不是很受信任/安全/同等实现的东西(在这个 jquery 中拯救了一天)),特别是因为有时你不能在客户端进行所有验证,你必须使用某种服务器端检查,比如(这个实体已经存在于数据库中?),并且支持禁用 js 的客户端,但正如我在开始时所说的那样视情况而定。
  • 我同意您不能在客户端进行所有验证,看起来验证框架似乎主要针对字段错误(太长,不是日期等)。至少在我见过的例子中。当您检查用户输入时,Javascript 似乎是进行检查的合适位置。
  • 我已经下定决心要进行 2 次调用而不是 1 次调用,因为它将详细信息部分视图与其下方的页面视图分离。我希望弹出窗口回复页面视图“我已关闭”,但不知道页面视图将要做什么。 jQuery 应该毫不费力地做到这一点。这使我不必担心对我的详细信息部分视图的更改会影响页面,反之亦然。

标签: jquery asp.net-mvc error-handling


【解决方案1】:

在 MVC3 中添加我喜欢的方法。使用您的编辑方法,您可以执行类似的操作

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) 
{
    Dinner dinner = dinnerRepository.GetDinner(id);
    try 
    {
        UpdateModel(dinner);
        dinnerRepository.Save();
        return Json (new { Success = true, Url = Url.Action("DetailsPartial", dinner), Div = "#DivToUpdateId" }); 
    }
    catch 
    {
        foreach (var issue in dinner.GetRuleViolations()) {
        ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
    }
        //I am replacing this with a partial view which will contain the model state errors. For people using MVC 3 with razor they should be able to use their normal views as partials
        return PartialView(dinner);
    }
}

然后你就可以使用成功函数,比如

success: function(data) {
    if (data.Success) {
        $.post(data.Url, function(partial) { 
            $(data.Div).html(partial);
        });
    }
    else
    {
        $('#formDiv').html(data)
    }
}

所以基本上,如果结果是 Json,那么 data.Success 为真。然后它使用 Url 中指定的操作结果更新 json (data.Div) 中指定的 div。如果结果不是 Json,则因为 post 方法失败并且 formDiv 更新为包含 ModelState 错误的部分表单。这是我用于对话框的方法,但效果很好。显然,对于 MVC3,我会更改一些编辑方法,例如使用 TryUpdateModel 等,但只是试图举例说明我的方法。通过传递 url 并发布方法的结果,无需尝试将 html 呈现为字符串以传递部分。

【讨论】:

  • 有趣。您能否发布您的 Edit PartialView 代码?
【解决方案2】:

如果我理解你想要做什么,我的第一个答案将是不,你不能使用模型状态,因为它是通过和 Ajax 请求。 也许您可以模拟 ModelState 行为,以显示错误:

  1. 通过 JSON 传递 List<KeyValuePair<string,string>> (property,message)(这将要求您将 modelErrors 从 modelState 传递到新结构)并通过 JS/jQuery 进行验证摘要的 HTML 构造(其中我认为是过度杀戮解决方案)。

  2. 1234563如果一切正常,只需返回 PartialDetails 视图并替换实际内容。这将需要某种状态参数,以便您知道在 ajax 回调中从服务器返回的内容。

编辑:最后一个选项听起来不错但很棘手,因为您需要通过 JSONResult 以字符串形式返回部分视图,这是关于该 hack Render a view as a string 的问题和解决方案。

就个人而言,我不认为使用 error 属性会有任何好处,我只是将它用于非常特定的情况,例如超时错误和服务器异常,而不是应用程序异常。

编辑: 使用 JSON

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(int id, FormCollection formValues)
        {
            Dinner dinner = dinnerRepository.GetDinner(id);
            try
            {
                UpdateModel(dinner);
                dinnerRepository.Save();
                return Json(new 
                {
                    result = "success",
                    html = this.RenderToString("PartialDetails", dinner) 
                });

            }
            catch
            {
                foreach (var issue in dinner.GetRuleViolations())
                {
                    ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
                }
                return Json(new
                {
                    result = "failed",
                    html = this.RenderToString("PartialEdit", dinner)
                });
            }
        }

这里的结果参数会让你知道在每种情况下要做什么,只需要在回调中检查它。

【讨论】:

  • 谢谢。然而,挑战的一部分是我真的更愿意将结果作为 PartialView 结果而不是 JSON 结果发回。对于 2.,您是否打了 2 个电话?一个返回成功/错误,另一个传递结果?这是我正在考虑的一种选择。
  • 它真的是一个调用,像 {"status": [{"code": "error"}], "html" : [{"html":"a lot of html"} ]}。如果你希望它只是一个 partialView Result 对象,为什么不直接返回孔 Edit partial View,以防模型出现错误?和详细信息部分视图,当没有发生错误时,模型状态将不会出现问题。
  • 使我的场景与大多数示例不同的部分是,我想根据是成功还是错误来执行两个非常不同的操作。如果是错误,我可以返回编辑部分视图并重新创建对话框。但是,如果成功,我想关闭对话框并刷新主页上的列表。所以客户端代码需要知道它是成功还是失败,以便知道要更新哪个对象——对话框还是列表。
  • 在这种情况下,我建议您改用 JSONResult 类型,因为普通的 PartialView 类型不会为您提供有关服务器端发生的情况的任何状态参考,除非您想做 2 个不同的请求一个用于统计信息,另一个用于部分视图。我用 Json 方法更新了帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-15
  • 2010-10-17
  • 2010-11-26
  • 1970-01-01
相关资源
最近更新 更多