如何正确处理子操作exception

我有一个返回PartialView的Action:

[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从Dictionary中返回一个视图。 如果用户请求不存在的选项卡,则会抛出KeyNotFoundexception,但是,在我的视图中,我得到以下exception:

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

 @using MyApplication.UI.Helpers.Html @model MyApplication.UI.Models.MyJobModel @{ ViewBag.Title = "Details"; } 

@Model.Blah

... *@ HttpException occurs here -- renders default error view *@ @Html.Action("TabInfo", new { id = ViewBag.Jobid, tab = ViewBag.Tab })

根据MS …

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

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

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

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

  1. 如果在GetViewModel方法中抛出exception,那么你的return语句甚至都不会得到处理,实际上因为没有catch语句你最终会在global.asax中的Application_Error中结束(如果你有一个当然的话)。

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

  3. 只需将结果放在一个变量中的ContainsKey上并声明该变量是真的吗? 或者您可以检查viewModel变量并Assert如果ContainsKey为false,那么请确保您的错误视图名称实际上在viewModel

try catch实际上并不是很好的做法,因为一般来说,如果你可以避免它,你应该使用额外的逻辑(比如在这个例子中的ContainsKey )防止发生exception。 例外情况适用于特殊情况:)。

在我的例子中,我在子操作中添加了一个ModelState错误(使用自定义消息而不是Exception的消息),并将ValidationSummary放在子操作的局部视图中。 由于父操作的摘要未获得错误,因此它不会复制错误。 当然,这仍然显示页面。 就我而言,它非常好。

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

当然,如果在调用PartialView时发生exception,比如cshtml中的错误,则无法返回操作并显示错误。 所以它不是一个完美的解决方案,但可能足以满足其他人的要求。

如果有其他人遇到这个问题。

我最终使用try / catch块来捕获KeyNotFoundexception。 我记录错误,然后将用户重定向到ErrorView。 在错误视图中,我使用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; }