如何正确处理子操作异常

本文关键字:操作 异常 理子 处理 何正确 | 更新日期: 2023-09-27 18:35:18

我有一个返回 Partial View 的操作:

[ChildActionOnly]
public ActionResult TabInfo(int id, string tab)
{
    ViewBag.Jobid = id;
    ViewBag.Tab = tab;
    var viewModel = _viewModelManager.GetViewModel(tab, id);
    return 
        PartialView(string.Format("~/Views/{0}/Index.cshtml", tab), viewModel);
}

_viewModelManager从字典返回视图。如果用户请求的选项卡不存在,则将抛出KeyNotFound异常,但是,在我看来,我得到以下异常:

Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'

@using MyApplication.UI.Helpers.Html
@model MyApplication.UI.Models.MyJobModel
@{
    ViewBag.Title = "Details";
}
<p>@Model.Blah</p>
...
*@ HttpException occurs here -- renders default error view *@
@Html.Action("TabInfo", new { id = ViewBag.Jobid, tab = ViewBag.Tab }) 

根据MS...

如果子操作本身发生异常,则会忽略子操作方法上的 HandleErrorAttribute 属性。因此,子操作应处理自己的异常。如果子操作应用了 AuthorizeAttribute 属性,则该属性将执行并返回 HTTP 未授权 401 状态代码。

我不能使用此[HandleError(ExceptionType = typeof(KeyNotFoundException), View="myError")],也不能使用 try/catch 重定向,因为不支持子操作的重定向。

处理子操作异常的最佳方法是什么?

底线:我想处理异常并返回自定义错误页面。

如何正确处理子操作异常

  1. 如果在 GetViewModel 方法中抛出异常,那么您的 return 语句甚至不会被处理,事实上,由于没有 catch 语句,您最终会在 global.asax 中Application_Error(当然,如果有的话)。

  2. 你是对的,你应该做一个ContainsKey检查,然后如果它是错误的,返回你的错误页面。

  3. 只需将结果放在变量中ContainsKeyAssert变量是否为真?或者,您可以检查viewModel变量并Assert如果ContainsKey为 false,请确保您的错误视图名称实际上在 viewModel 中。

一般来说,try catch并不是很好的做法,如果可以避免它,则应使用其他逻辑(如本例中的ContainsKey)防止异常发生。例外情况是特殊情况:)。

就我而言,我在子操作中添加了一个 ModelState 错误(使用自定义消息而不是异常的消息),并在子操作的部分视图中放置验证摘要。 由于父操作的摘要未获取错误,因此不会重复错误。 当然,这仍然会显示页面。 就我而言,这完全没问题。

但是你要确保你没有在儿童动作return PartialView(modelContainingPotentiallySensitiveInfo)中做这样的事情。 我无法想象特定的场景,但通常您定向到完全不同的错误页面的原因首先是为了防止与错误相关的安全漏洞。 因此,如果您使用我的技术,请确保创建一个新的空模型(尚未从数据库中查询的模型)以传递到部分页面。

当然,如果在调用 PartialView 时发生异常,例如 cshtml 中的错误,则无法返回操作并显示错误。 因此,这不是一个完美的解决方案,但对其他人来说可能就足够了。

以防其他人遇到这个问题。

我最终使用try/catch块来捕获KeyNotFound异常。我记录错误,然后将用户重定向到错误视图。在错误视图中,我使用 javascript 将用户重定向到相应的视图。

[ChildActionOnly]
    public ActionResult TabInfo(int id, string tab, string jobno)
    {
        try
        {
            var viewModel = _viewModelManager.GetViewModel(tab, id);
            ViewBag.Jobid = id;
            ViewBag.Tab = tab;
            return PartialView(string.Format("~/Views/{0}/Index.cshtml", tab), viewModel);
        }
        catch (Exception ex)
        {
            return View("Error");
        }
    }

错误视图

@model System.Web.Mvc.HandleErrorInfo
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <script type="text/javascript">
        window.location.href = '@Url.Content("~/400.htm")';
    </script>
</body>
</html>